Преамбула: хранилище и объекты — это разные понятия в C++. Хранилище относится к пространству в памяти, а объекты – это сущности с продолжительностью жизни, которые могут создаваться и уничтожаться в пределах части хранилища. Хранилище может быть повторно использовано для размещения нескольких объектов с течением времени. Все объекты требуют хранения, но может быть хранилище без объектов.
c правильно. Placement-new — это один из допустимых методов создания объекта в хранилище (C++14 [intro.object]/1), даже если в этом хранилище уже существовали объекты. Старые объекты неявно уничтожаются при повторном использовании хранилища, и это совершенно нормально, если у них нет нетривиальных деструкторов ([basic.life]/4). new(a) float;
создает объект типа float
и динамической длительности хранения в существующем хранилище ([expr.new]/1).
d и e не определены из-за упущения в текущих правилах объектной модели: эффект доступа к памяти через выражение glvalue определяется только тогда, когда это выражение ссылается на объект; а не когда выражение относится к хранилищу, не содержащему объектов. (Примечание: просьба не оставлять неконструктивных замечаний по поводу очевидной неадекватности существующих определений).
Это не означает, что «malloc бесполезен»; эффект malloc
и operator new
заключается в получении хранилища. Затем вы можете создавать объекты в хранилище и использовать эти объекты. На самом деле именно так работают стандартные распределители и выражение new
.
a и b являются строгими нарушениями псевдонимов: значение gl типа float
используется для доступа к объектам несовместимого типа char
. ([базовый.lval]/10)
Есть предложение, которое сделает все случаи четко определены (кроме выравнивания a, упомянутого ниже): в соответствии с этим предложением использование *f
неявно создает объект этого типа в местоположении с некоторыми оговорками.
Примечание. В случаях с b по e проблем с выравниванием не возникает, потому что new-expression и ::operator new
гарантированно выделяют память, правильно выровненную для любого типа ([new.delete. сингл]/1).
Однако в случае std::vector<char>
, несмотря на то, что стандарт указывает, что ::operator new
вызывается для получения памяти, стандарт не требует, чтобы первый элемент вектора помещался в первый байт этой памяти; например вектор может решить выделить 3 дополнительных байта впереди и использовать их для некоторой бухгалтерии.
person
M.M
schedule
26.10.2017
char
освобождены от проблемы строгого псевдонима. Однако выравнивание все еще остается проблемой. - person molbdnilo   schedule 26.10.2017char *
для проверки любого значения. Обратное не обязательно верно. - person geza   schedule 26.10.2017c()
, недопустимо, потому что вам нужно использовать размещениеnew
для создания объекта, а не толькоreinterpret_cast
, и все отa()
доc()
недействительны из-за выравнивания. Хотя я не настолько уверен ни в том, ни в другом. Допустимой версией будетvoid f() { char *a = (char*)malloc(sizeof(float)); float *f = new(a) float; *f = 42; }
; иmalloc
, иoperator new
из стандартной библиотеки гарантированно имеют достаточное выравнивание. - person Daniel H   schedule 26.10.2017char
можно использовать для проверки любого значения. Выражениеchar
может быть получено путем разыменования выраженияchar *
, хотя есть и другие способы. Выражениеchar *
нельзя использовать напрямую для проверки любого значения. - person M.M   schedule 27.10.2017