Сохраняет ли C++ default-initialization предшествующую нулевую инициализацию?

Если конструктор C++ для объекта со статической продолжительностью хранения не инициализирует элемент, требуется ли это для сохранения предыдущей инициализации нуля или он оставляет элемент с неопределенным значением?

Мое чтение спецификации C++ заключается в том, что она противоречит сама себе.

Пример:

#include <iostream>

struct Foo { Foo(); int x; } object;

Foo::Foo() { }

int main() { std::cout << object.x << std::endl; }

Конструктор Foo() явно не инициализирует член object.x, поэтому, согласно примечанию в параграфе 8 12.6.2:

член имеет неопределенную ценность.

Но работая с деталями различных инициализаций, это кажется неправильным. Элемент object.x инициализируется нулями, так как он имеет static-storage-duration, и тогда я не вижу ничего, что изменило бы это.

Что касается конструктора, то применяется текст в 12.6.2:

объект инициализируется по умолчанию.

В п. 7 8.5 соответствующий случай инициализации по умолчанию:

... инициализация не выполняется

что я прочитал, чтобы означать, что предыдущая инициализация нуля не изменяется при инициализации по умолчанию.

Я пропускаю какой-то другой текст, который сбрасывает все элементы в "неопределенное значение" в начале вызова конструктора?

Я обнаружил различные другие вопросы о стековом потоке, касающиеся нулевой инициализации и инициализации по умолчанию, но я не смог найти ни одного, который анализировал бы то, что происходит, когда инициализация по умолчанию следует за некоторой ранней инициализацией того же объекта.

В этом случае, вероятно, нет практического эффекта. Но в более сложном конструкторе, когда некоторые члены инициализированы, а другие нет, должен ли компилятор точно отслеживать, какие байты / биты инициализированы? Или он может просто инициализировать весь объект (например, упростив конструктор до вызова memset())?

1 ответ

Решение

Сообщение о дефекте 1787 года привело к изменению, задокументированному в N3914, к проекту стандарта для C++14. Какие изменения [dcl.init] параграф 12 из:

Если для объекта не указан инициализатор, объект инициализируется по умолчанию; если инициализация не выполняется, объект с автоматическим или динамическим сроком хранения имеет неопределенное значение. [Примечание: объекты со статическим или потоковым хранением инициализируются нулями, см. 3.6.2. - конец примечания]

чтобы:

Если для объекта не указан инициализатор, объект инициализируется по умолчанию. При получении хранилища для объекта с автоматической или динамической продолжительностью хранения объект имеет неопределенное значение, и если для объекта не выполняется инициализация, этот объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено (5.17 [expr.ass]), [Примечание: объекты со статическим или потоковым хранилищем инициализируются нулями, см. 3.6.2 [basic.start.init]. - примечание] Если в результате оценки получено неопределенное значение, поведение не определено, за исключением следующих случаев:

[...]

Это проясняет ситуацию неопределенного значения только для объектов автоматической или динамической длительности хранения. Поскольку это было применено в отчете о дефектах, оно, вероятно, также применимо к C++11, так как отчет о дефектах возник до того, как был принят C++14, но он также может применяться и в дальнейшем. Правила того, как далеко должен применяться дефект, никогда не были мне ясны.

Так как в комментариях было упомянуто место размещения new, то же изменение также изменило раздел [expr.new], сделав часть с неопределенным значением комментарием:

Если новый инициализатор опущен, объект инициализируется по умолчанию (8.5 [dcl.init]); если. [Примечание: если инициализация не выполняется, объект имеет неопределенное значение. —Конечная записка]

В начале раздела говорится:

[...] Объекты, созданные новым выражением, имеют динамическую продолжительность хранения (3.7.4).[...]

Которого кажется достаточным, чтобы применить изменения в разделе [dcl.init].

Это изменение было также интересно, так как до этого термина термин " неопределенное значение" не был определен в стандарте C++.

Другие вопросы по тегам