June 8th, 2007

nyaload

C++, zero initialization

С++: Безопасный для поддержки и дальнейшей жизни проекта способ инициализации структуры из ста полей нулями.

http://www.everfall.com/paste/id.php?6ug9lmemxk29

T x = {}; //рекомендуется для типов без конструкторов

если конструктора и наследования нет, будет вызов дефолтных конструкторов/обнуление членов ("each member of the aggregate shall be initialized with a value of the form T()").
Если есть, компилятор ругнётся, но покрайней мере не будет никаких сюрпризов, которые могли бы быть если сделать:

T x = T(); //перестанет обнулять int-float члены встроеных типов, если добавить в T non-pod член или конструктор по умолчанию.
или
memset(&x, 0, sizeof(x)); //будет вести себя странно как только в T появятся виртуальные функции или non-pod члены.

Более точная информация - С++ Стандарт, 8.5.1 Aggregates

К сожалению, такой способ инициализации доставляет некоторые неудобства, когда сложно завести временную переменную, и надо инициализировать базовый класс или член или параметр функции (см. пример с http://www.everfall.com/paste/id.php?6ug9lmemxk29).
Можно обойти с помощью template <class T> T InitAggregate() { T x = {}; return x; }

PS. Если внутри T - под-члены с конструктором который оставляет неинициализированый мусор, то добраться до них можно только при помощи memset. Типичный пример:
Collapse )

PPS. не люблю C++ за то, что вокруг каждой мелочи столько граблей и тайных знаний.

PPPS. В VC2005 появился __is_pod(type), __is_polymorphic(type)
. Можно ещё ставить ассерты перед memset.

PPPPS.
Справедливо напомнили, что если создаём не автоматические объекты на стеке, то можно занулить память перед созданием в ней объекта. Подумалось о ZeroBefore<T>, который обнуляет память _перед_ созданием объекта T в своём чреве. Но "как-то всё это через хитро закрученую жопу".

PPPPPS.
Справедливо напомнили, что в эльфийских рассылках usenet существуют странные компьютеры, где нулевой float и нулевой указатель не обязательно состоят из нулевых байтов, как ещё одна рекомендация не использовать memset.