Это неопределенное поведение для инициализации данных перед размещением новых? - PullRequest
0 голосов
/ 12 декабря 2018
struct A { //POD class
    char data[10];
    void print() {std::cout << data;}
};
int main() {
    char buffer[11] = "HELLO"; //sets values in buffer
    A* a = new(buffer)A;
    a->print(); // read from memory buffer
    a->~A();
}

С точки зрения класса, это чтение из неинициализированной памяти, но с точки зрения памяти, память фактически была инициализирована.Это неопределенное поведение или просто опасно?

[Примечание.определенный буфер в памяти.Это было vector делает под прикрытием для создания классов во внутреннем буфере]

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Состояние буфера после создания объекта не определено.Компиляторы могут свободно писать "format c;:" во время создания A.Они также могут оптимизировать предварительную загрузку буфера, просто отбрасывая то, что вы сделали в этой строке.

Ваш код print будет тогда UB, так как << ожидает буфер с нулевым окончанием.

0 голосов
/ 13 декабря 2018

Хотя компилятору, как правило, ничего не стоит интерпретировать новое размещение как «импорт» любых битовых шаблонов, которые бывают в хранилище до создания объекта, существуют некоторые трудно охарактеризованные угловые случаи, когда это можетзначительно усложнить или помешать оптимизации, не предлагая никакой реальной выгоды.Таким образом, Стандарт позволяет компиляторам импортировать битовые комбинации в тех случаях, когда это ничего не будет стоить или принесет пользу их клиентам, без необходимости делать это в случаях, которые будут дорогостоящими без выгоды для их клиентов.

Хотя это будетбыло бы полезно, если бы существовала форма размещения нового синтаксиса, который бы явно указывал, что битовые шаблоны должны быть импортированы, такая вещь не считалась необходимой при написании Стандарта.В большинстве случаев, когда импорт битовых шаблонов был бы полезен, это ничего не стоило бы, и компиляторы делали это независимо от того, были ли они обязательны или нет.В случаях, когда это будет бесполезно, не имеет значения, поддерживают ли компиляторы такое поведение.Ситуации, в которых такой синтаксис приводил бы к тому, что компиляторы делали что-то полезное, что они не делали бы в противном случае, были достаточно редкими, чтобы не было необходимости их учитывать.

Очевидно, что философия компилятора изменилась за десятилетия с момента размещения новогосначала стандартизированы, и ситуации, когда побитовый импорт был бы полезен, но компиляторы не могли бы надежно его поддерживать, встречаются гораздо чаще.Разумным решением было бы добавить две новые синтаксические формы - одну, которая потребовала бы, чтобы компилятор импортировал битовую комбинацию, а другую, которая явно указала бы, что битовая комбинация не имеет значения - на основе того, что программист, вероятно, будет знать большео том, имеют ли значение битовые шаблоны, чем мог бы написать автор компилятора.Однако до сих пор этого еще не произошло, в результате чего конструкции, подобные вашей, находятся в неловком состоянии и могут быть эффективно поддержаны некоторыми реализациями, но не другими, без какого-либо приятного способа определения реализаций, которые их поддерживают.

0 голосов
/ 12 декабря 2018

Несмотря на то, что член класса и массив гарантированно имеют один и тот же адрес в данном конкретном случае (на основе [basic.compound] /4.3 плюс тот факт, что требования к new-expression s на самом деле не позволяет компилятору делать что-либо еще, кроме как помещать этот объект в начало вашего буфера), я почти уверен, что это неопределенное поведение.

Я полагаю, что соответствующий бит стандарта будет basic.memobj §1 :

Когда получено хранилище для объекта с автоматической или динамической продолжительностью хранения, объект имеетнеопределенное значение, и если для объекта не выполняется инициализация, этот объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено ([expr.ass]).

Я не знаю каких-либо дополнительных формулировокгде-нибудь в стандарте, который в любом случае давал бы гарантии относительно первоначальной стоимости объекта на основе того, что было внутри хранилища, в котором он был создан до егоНачалось fetime.Ваш объект инициализирован по умолчанию и имеет тип класса, поэтому будет вызван конструктор по умолчанию.Для элемента в вашем конструкторе нет mem-initializer , а также в классе нет инициализатора по умолчанию, поэтому элемент будет инициализирован по умолчанию [class.base.init / 9.3] .Поскольку элементы массива имеют фундаментальный тип, инициализация для них не будет выполняться .Это означает, что basic.indet §2 применяется к любому использованию содержимого массива (что может произойти внутри operator <<)

Если неопределенное значение создаетсяоценка, поведение не определено, за исключением следующих случаев […]

Поскольку ваш случай не соответствует ни одному из случаев, перечисленных в качестве исключений, ваша программа должна иметь неопределенное поведение…

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...