Размещение новых и неинициализированных участников POD

Гарантирует ли стандарт C ++, что неинициализированные члены POD сохраняют свое прежнее значение после размещения нового?

Или, точнее, будет ли всегда выполняться следующее утверждение согласно C ++ 11?

#include <cstdlib>
#include <cassert>

struct Foo {
int alpha; // NOTE: Uninitialized
int beta = 0;
};

int main()
{
void* p = std::malloc(sizeof (Foo));
int i = some_random_integer();
static_cast<Foo*>(p)->alpha = i;
new (p) Foo;
assert(static_cast<Foo*>(p)->alpha == i);
}

Одинаков ли ответ для C ++ 03?

14

Решение

Гарантирует ли стандарт C ++, что неинициализированные члены POD сохраняют свое прежнее значение после размещения нового?

Будет ли всегда выполняться следующее утверждение в соответствии с C ++ 11?

Нет.

Неинициализированные члены данных имеют неопределенный значение, и это совсем не то же самое, что сказать, что базовая память остается одна.

[C++11: 5.3.4/15]: новое выражение который создает объект типа T инициализирует этот объект следующим образом:

  • Если новый инициализатор опущен, объект по умолчанию инициализируется (8.5); если инициализация не выполняется, объект имеет неопределенное значение.
  • В противном случае новый инициализатор интерпретируется в соответствии с правилами инициализации 8.5 для прямой инициализации.

[C++11: 8.5/6]: По умолчанию инициализировать объект типа T средства:

  • если T это (возможно, резюме квалифицированных) тип класса (Пункт 9), конструктор по умолчанию для T называется (и инициализация плохо сформирована, если T не имеет доступного конструктора по умолчанию);
  • если T тип массива, каждый элемент инициализируется по умолчанию;
  • в противном случае инициализация не выполняется.

[C++11: 12.1/6]: Конструктор по умолчанию, который по умолчанию и не определен как удаленный, неявно определяется, когда он УСО используемый (3.2) создать объект своего типа (1.8) или когда он явно установлен по умолчанию после первого объявления. Неявно определенный конструктор по умолчанию выполняет набор инициализаций класса, который
выполняется пользовательским конструктором по умолчанию для этого класса без т е р-инициализатор (12.6.2) и пустой компаунд-заявление.

[C++11: 12.6.2/8]: В не делегирующем конструкторе если данный нестатический член данных или базовый класс не обозначен мем-инициализатор-идентификатор (включая случай, когда нет мем-инициализатора-лист потому что конструктор не имеет т е р-инициализатор) и сущность не является виртуальным базовым классом абстрактного класса (10.4), то

  • если объект является нестатическим членом данных, который имеет скобки или равно-инициализатор, объект инициализируется, как указано в 8.5;
  • в противном случае, если объект является вариантом члена (9.5), инициализация не выполняется;
  • в противном случае объект инициализируется по умолчанию (8.5).

(NB. первый вариант в 12.6.2/8 как ваш член beta обрабатывается)

[C++11: 8.5/6]: По умолчанию инициализировать объект типа T средства:

  • если T это (возможно резюме квалифицированных) тип класса (раздел 9), конструктор по умолчанию для T называется (и инициализация плохо сформирована, если T не имеет доступного конструктора по умолчанию);
  • если T тип массива, каждый элемент инициализируется по умолчанию;
  • в противном случае инициализация не выполняется.

[C++11: 8.5/11]: Если для объекта не указан инициализатор, объект инициализируется по умолчанию; если инициализация не выполняется, объект с автоматическим или динамическим сроком хранения имеет неопределенное значение.

Компилятор может выбрать обнуление (или иное изменение) основной памяти во время выделения. Например, известно, что Visual Studio в режиме отладки записывает распознаваемые значения, такие как 0xDEADBEEF в память, чтобы помочь отладке; в этом случае вы, вероятно, увидите 0xCDCDCDCD который они используют для обозначения «чистой памяти» (ссылка).

Будет это в этом случае? Я не знаю. Я не думаю, что мы Можно знать.

Что мы делать Я знаю, что C ++ не запрещает это, и я считаю, что это приводит нас к выводу об этом ответе. 🙂


Одинаков ли ответ для C ++ 03?

да, хотя по несколько иной логике:

[C++03: 5.3.4/15]: новое выражение который создает объект типа T инициализирует этот объект следующим образом:

  • Если новый инициализатор опущен:
    • Если T это (возможно, резюме квалифицированных) класс не POD (или его массив), объект инициализируется по умолчанию (8.5). Если T является const-квалифицированным типом, базовый тип класса должен иметь объявленный пользователем конструктор по умолчанию.
    • В противном случае созданный объект имеет неопределенное значение. Если T является константным типом, или (возможно резюме квалифицированных) Тип класса POD (или его массив), содержащий (прямо или косвенно) член типа с константой, программа некорректна;
  • Если новый инициализатор имеет форму ()элемент инициализируется значением (8.5);
  • Если новый инициализатор имеет форму (expression-list) а также T является типом класса, соответствующий конструктор вызывается, используя expression-list в качестве аргументов (8.5);
  • Если новый инициализатор имеет форму (expression-list) а также T является арифметикой, перечислением, указателем или указателем на член типа и expression-list содержит ровно одно выражение, затем объект инициализируется (возможно, преобразованным) значением выражения (8.5);
  • В противном случае новое выражение плохо сформирован.

Теперь все это было моим строгий интерпретация правил инициализации.

Говоря практически, я думаю, что вы, вероятно, правы, видя потенциальный конфликт с определением размещения operator new синтаксис:

[C++11: 18.6.1/3]: Примечания: Преднамеренно не выполняет никаких других действий.

В следующем примере объясняется, что размещение new msgstr «может быть полезно для построения объекта по известному адресу».

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

Кроме того, он может просто запретить оператор Сам не предпринимать никаких действий, оставляя распределитель свободным для. Это делает Мне кажется, что важный момент, который пытается сделать стандарт, заключается в том, что новая память не выделяется.

Независимо от того, доступ к этим данным вызывает неопределенное поведение:

[C++11: 4.1/1]: Glvalue (3.10) нефункционального типа, не являющегося массивом T может быть преобразован в prvalue. Если T является неполным типом, программа, которая требует этого преобразования, плохо сформирована. Если объект, на который ссылается glvalue, не является
объект типа T и не является объектом типа, полученного из T, или же если объект неинициализирован, программа, которая требует этого преобразования, имеет неопределенное поведение. Если T это тип, не относящийся к классу, тип prvalue — версия cv-unqualified T, В противном случае тип prvalue T,

Так это не имеет значения: вы все равно не могли бы соблюдать оригинальное значение.

20

Другие решения

C ++ 11 12.6.2 / 8 «Инициализация баз и членов» гласит:

В не делегирующем конструкторе, если данный нестатический элемент данных или
базовый класс не обозначается идентификатором mem-initializer-id (включая
случай, когда нет mem-initializer-list, потому что конструктор
не имеет инициализатора ctor), и объект не является виртуальным базовым классом
абстрактный класс (10.4), тогда

  • если объект является нестатическим элементом данных, который имеет инициализатор с фигурной или равной скобкой, объект инициализируется, как указано в
    8,5;
  • в противном случае, если объект является вариантом члена (9.5), инициализация не выполняется;
  • в противном случае объект инициализируется по умолчанию (8.5).

Инициализация по умолчанию на int ничего не делает (8.5 / 6 «Инициализаторы»):

По умолчанию инициализировать объект типа T означает:

  • если T является (возможно, cv-квалифицированным) типом класса (раздел 9), вызывается конструктор по умолчанию для T (и инициализация
    плохо сформирован, если T не имеет доступного конструктора по умолчанию);
  • если T является типом массива, каждый элемент инициализируется по умолчанию;
  • в противном случае инициализация не выполняется.

Итак, член alpha должен быть оставлен в покое.

0

По вопросам рекламы [email protected]