В C++11, вы всегда можете (безопасно) заменить инициализацию memset() пустым инициализатором?
Я часто сталкиваюсь с POD-структурами в коде, которые вручную инициализируются нулями memset
вот так:
struct foo;
memset(&foo, 0, sizeof(foo));
Я проверил стандарт C++11 и он говорит: "Объект, инициализатор которого представляет собой пустой набор скобок, то есть (), должен быть инициализирован значением". Далее следует: "Инициализировать значение [структура pod] типа T означает... объект инициализируется нулями".
Итак... означает ли это, что вы всегда можете безопасно сжать приведенный выше код до следующего:
struct foo{};
И иметь гарантированно инициализированную структуру, как если бы вы вызвали memset(&foo, 0, ...)
?
Если это так, то, вообще говоря, можете ли вы безопасно инициализировать что-либо с пустыми инициализаторами, например, так:
SomeUnknownType foo{}; // will 'foo' be completely "set" to known values?
Я знаю, что это не всегда было возможно в C++03 (до унифицированного синтаксиса инициализации), но возможно ли это сейчас в C++11 для любого типа?
2 ответа
Вы можете, конечно, инициализировать любой стандартный тип макета, используя пустые скобки, и получить его инициализированным нулем. К сожалению, после добавления конструкторов в изображение это не обязательно так:
struct foo {
int f;
};
struct bar {
int b;
bar() {}
};
foo f{};
bar b{};
В то время как f.f
инициализируется нулем, b.b
неинициализирован. Однако с этим ничего не поделаешь bar
потому что ты не можешь memset()
это тоже. Это должно быть исправлено.
Memset инициализирует его до 0, но пустые скобки будут означать инициализацию вашего объекта (есть разница).
Цитирование из стандарта:
Инициализировать значение объекта типа T означает:
- если T является типом класса с конструктором, объявленным пользователем, то вызывается конструктор по умолчанию для T (и инициализация некорректна, если у T нет доступного конструктора по умолчанию);
Кроме того, делая struct foo{};
безопасен и заботится о том, чтобы не сбрасывать указатель виртуальной таблицы.
Но делать memset(&foo, 0, sizeof(foo));
В случае виртуальных функций это действительно очень плохо, так как он сбрасывает указатель на виртуальную таблицу.