Пустые конструкторы всегда вызываются в C ++? - PullRequest
7 голосов
/ 24 февраля 2011

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

class NoConstructor  
{  
    int member;  
};  

class EmptyConstructor  
{  
    int member;  
};

class InitConstructor  
{  
    InitConstructor()  
        : member(3)   
    {}  
    int member;  
};

int main(int argc, _TCHAR* argv[])  
{  
    NoConstructor* nc = new NoConstructor(); //will this call the generated constructor?  
    EmptyConstructor* ec = new EmptyConstructor(); //will this call the empty constructor?  
    InitConstructor* ic = new InitConstructor(); //this will call the defined constructor  

    EmptyConstructor* ecArray = new EmptyConstructor[100]; //is this any different?
}

Я много занимался поиском и провел некоторое время, просматривая сгенерированный код сборки в Visual Studio. В сборках релизов может быть сложно следовать.

В итоге: Всегда ли конструктор вызывается? Если так, то почему?

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

Ответы [ 5 ]

15 голосов
/ 24 февраля 2011

будет ли всегда вызываться созданный компилятором конструктор / пустой конструктор, когда вы создаете экземпляр объекта?

Нет.Если ваш класс является так называемым «POD» (обычные старые данные), то сгенерированный компилятором конструктор не будет вызываться всегда.

В частности, он не будет вызываться вдва следующих случая:

struct Pod {
    int x;
};

int main() {
    Pod pod;
    std::cout << pos.x << std::endl; // Value undefined.

    Pod pod2 = Pod(); // Explicit value initialization.


    Pod* pods = new Pod[10];
    // Values of `pods` undefined.

    Pod* pods2 = new Pod[10](); // Explicit value initialization.
}

Условия, когда точно тип является POD, немного хитры.В C ++ FAQ есть хорошая разбивка .

10 голосов
/ 24 февраля 2011

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

5 голосов
/ 24 февраля 2011

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

Если в вашем классе есть не-POD члены, для которых нужно вызывать конструкторы, компилятор сгенерирует конструктор по умолчанию, который вызывает конструкторы членов. Но даже тогда - он не будет инициализировать типы POD. То есть если вы не инициализируете member явно, вы можете оказаться там с мусором.

Все это может получить даже фантазии, если ваш компилятор / компоновщик имеет LTO.

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

Вот разборка кода в вашем примере (x86_64, gcc 4.4.5):

main:
    subq    $8, %rsp
    movl    $4, %edi
    call    _Znwm
    movl    $4, %edi
    movl    $0, (%rax)
    call    _Znwm
    movl    $4, %edi
    movl    $0, (%rax)
    call    _Znwm
    movl    $400, %edi
    movl    $3, (%rax)
    call    _Znam
    xorl    %eax, %eax
    addq    $8, %rsp
    ret

Как видите, конструкторов вообще не вызывается. Классов вообще нет, каждый объект представляет собой целое число в 4 байта.

С компилятором MS, YMMV. Таким образом, вы должны проверить разборку самостоятельно. Но результат должен быть похожим.

Удачи!

1 голос
/ 24 февраля 2011

Определенные типы классов или структур называются POD «Простые старые данные» в C ++.Эти типы не будут иметь вызываемые конструкторы.

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

0 голосов
/ 24 февраля 2011

Ваш образец не очень хорош, вы пропустили ключевое слово public в классах примеров, и более того, в ваших примерах принудительная инициализация нуля, написав CLASS * class = new CLASS(); вместо CLASS * class = new CLASS;.

В указанном вами коде - инициализация нуля всегда будет выполняться в соответствии с требованиями стандарта.Вы можете называть его так, как хотите, - но БУДЕТ код, гарантирующий правила стандарта.

Если бы вы спросили, не показывая этот спорный пример кода, тогда единственным правильным ответом будет - compiler specific.

...