Есть неявный конструктор по умолчанию в C++?


в книге, которую я читаю в данный момент (C++ Без Страха) Он говорит, что если вы не объявляете конструктор по умолчанию для класса, компилятор предоставляет один для вас, который "обнуляет каждый член данных". Я экспериментировал с этим, и я не вижу никакого обнуления поведения. Я тоже не могу найти ничего об этом на Google. Это просто ошибка или особенность конкретного компилятора?

11 58

11 ответов:

Если вы не определяете конструктор, компилятор определит конструктор по умолчанию для вас.

реализация этого

конструктор по умолчанию:

  • по умолчанию построить базовый класс (если базовый класс не имеет конструктора по умолчанию, это компиляция неудачи)
  • по умолчанию построить каждую переменную-член в порядке объявления. (Если элемент не имеет конструктора по умолчанию, это компиляция неудача.)

Примечание:
Данные POD (int, float, pointer и т. д.) у вас нет явного конструктора, но действие по умолчанию-ничего не делать (в флюгере философии C++; мы не хотим платить за что-то, если мы явно не просим об этом).

Если деструктор/конструктор копирования/оператор присваивания не определен, компилятор создает один из них для вас (поэтому класс всегда имеет деструктор / конструктор копирования / оператор присваивания (если вы не обманываете и явно объявить один, но не определить его)).
Реализация по умолчанию:

деструктор:

  • если определен пользовательский деструктор, выполните указанный код.
  • вызовите деструктор каждого члена в обратном порядке объявления
  • вызов деструктора базового класса.

Конструктор Копирования:

  • вызовите конструктор копирования базового класса.
  • вызов конструктора копирования для каждого переменная-член в порядке объявления.

Оператор Присваивания:

  • вызовите оператор присваивания базового класса
  • вызовите оператор присваивания каждой переменной-члена в порядке объявления.
  • вернуть ссылку на это.

Примечание оператор копирования / присваивания данных POD просто копирует данные (следовательно, проблема неглубокого копирования, связанная с необработанными указателями).

Я думаю, стоит отметить, что конструктор по умолчанию создается только компилятором, если вы предоставите никакой конструктор. Это означает, что если вы только один конструктор, который принимает аргумент, компилятор не создайте конструктор no-arg по умолчанию для вас.

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

  • компилятор автоматически создает конструктор по умолчанию?
  • выполняет ли неявно созданный конструктор по умолчанию ноль инициализация?

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

случай "без конструкции" на самом деле просто формальность, потому что он функционально ничем не отличается от вызова тривиальные конструктор по умолчанию. Другой случай более интересен: инициализация значения по члену вызывается с помощью "() " [as если явно вызывается конструктор, который не имеет аргументов] и он обходит то, что технически называется the конструктор по умолчанию. Вместо этого он рекурсивно выполняет инициализацию значений для каждого элемента данных, и для примитивных типов данных это в конечном итоге решает ноль-инициализации.

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

    MyClass a; // default-construction or no construction
    MyClass b = MyClass(); // member-wise value-initialization

и

    new MyClass; // default-construction or no construction
    new MyClass(); // member-wise value-initialization

Примечание: Если a пользователей-заявил конструктор по умолчанию тут exist, затем инициализация значения по члену просто вызывает это и останавливается.


вот несколько подробная разбивка того, что говорит стандарт об этом...

  • если вы не объявите конструктор, компилятор неявно создает конструктор по умолчанию [12.1-5]

  • конструктор по умолчанию не инициализировать примитивные типы [12.1-7]

    MyClass() {} // implicitly defined constructor
    
  • если вы инициализируете объект с помощью " ()", это не вызывает непосредственно конструктор по умолчанию. Вместо этого он инициирует длинную последовательность правил, называемых значением-инициализации [8.5-7]

  • чистый эффект инициализации значения заключается в том, что неявно объявленный конструктор по умолчанию не вызывается. Вместо этого вызывается рекурсивная инициализация значения по элементам, которая в конечном итоге ноль-инициализировать любые примитивные члены и вызывает конструктор по умолчанию для всех членов, которые имеют объявленный пользователем конструктор [8.5-5]

  • инициализация значений применяется даже к примитивным типам - они будут инициализированы нулем. [8.5-5]

    a = int(); // equivalent to int a=0;
    

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

так когда это случилось?

  • могут быть обстоятельства, когда общий код хочет принудительно инициализировать неизвестные типы. Инициализация значения предоставляет способ сделать это. Просто помните, что неявная нулевая инициализация не происходит, если пользователь предоставил конструктор.

  • по умолчанию данные, содержащиеся в std::vector, инициализируются значением. Это может помешать отладчикам памяти идентифицировать логические ошибки, связанные с неинициализированными буферы памяти.

    vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
    
  • целые массивы примитивов типа или структур типа" простые старые данные " (POD) могут быть инициализированы нулем с помощью синтаксиса инициализации значений.

    new int[100]();
    

этот пост подробнее о различиях между версиями стандарта, и он также отмечает случай, когда стандарт применяется по-разному в крупных компиляторы.

C++ создает конструктор по умолчанию, но только если вы не предоставляете свой собственный. В стандарте ничего не говорится об обнулении членов данных. По умолчанию при первом создании любого объекта они не определены.

Это может быть запутанным, потому что большинство примитивных типов C++ имеют "конструкторы" по умолчанию, которые инициализируют их до нуля (int (), bool (), double (), long (), etc.), но компилятор не вызывает их для инициализации POD членов, как это делает для объекта члены.

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

конструктор по умолчанию для класса не будет инициализировать встроенные типы, но он будет вызывать конструктор по умолчанию для всех пользовательских члены:

class Foo
{
public:
     int x;
     Foo() : x(1) {}
};

class Bar
{
public:
     int y;
     Foo f;
     Foo *fp;
};

int main()
{

    Bar b1; 
    ASSERT(b1.f.x == 1); 
    // We know nothing about what b1.y is set to, or what b1.fp is set to.

    // The class members' initialization parallels normal stack initialization.
    int y;  
    Foo f; 
    Foo *fp; 
    ASSERT(f.x == 1);
    // We know nothing about what y is set to, or what fp is set to.

}

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

В C++ (и C) содержание любых выделенных данных не гарантируется. В конфигурациях отладки некоторые платформы установят это в известное значение (например, 0xFEFEFEFE), чтобы помочь идентифицировать ошибки, но на это не следует полагаться.

обнуление происходит только для глобалов. Поэтому, если ваш объект объявлен в глобальной области видимости, его члены будут обнулены:

class Blah
{
public:
    int x;
    int y;
};

Blah global;

int main(int argc, char **argv) {
    Blah local;
    cout<<global.x<<endl;  // will be 0
    cout<<local.x<<endl;   // will be random
}

C++ нет не гарантия обнуления памяти. Java и C# делают (в некотором роде).

некоторые компиляторы могут, но не зависим от этого.

C++ создает конструктор по умолчанию. При необходимости (определяется во время компиляции, я считаю), он также будет генерировать конструктор копирования по умолчанию и конструктор назначения по умолчанию. Я ничего не слышал о гарантиях для обнуления памяти.

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

для конструктора, чтобы быть нетривиальным конструктором, ниже приведены условия, в которых любой может быть достаточно:

1) класс имеет виртуальную функцию-член. 2) член класса подобъекты или базовые классы имеют нетривиальные конструкторы. 3) класс имеет виртуальный иерархия наследования.

в C++11 конструктор по умолчанию, созданный компилятором, помечается как удаленный, если:

  • класс имеет ссылочное поле
  • или поле const без определяемого пользователем конструктора по умолчанию
  • или поле без инициализатора по умолчанию, с удаленным конструктором по умолчанию

http://en.cppreference.com/w/cpp/language/default_constructor