scdmb
scdmb

Reputation: 15631

Copy constructor and normal constructor for non-POD type

There is this code:

#include <iostream>

class KlasaNiePOD{
public:
    int a;
    ~KlasaNiePOD(){}

};
int main() {
    KlasaNiePOD obiekt1; // first case
    std::cout << obiekt1.a << std::endl; // -1075234152
    KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case
    std::cout << obiekt2.a << std::endl; // 0
    return 0;
} 

Why in the first case 'a' is not initialized, but in second case it is? Shouldn't be called constructor always in non-POD classes?

Edit:

Fragment from assembly:

.globl main
    .type   main, @function
main:
.LFB960:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    .cfi_lsda 0x0,.LLSDA960
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    pushl   %esi
    pushl   %ebx
    subl    $40, %esp
    movl    28(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $_ZSt4cout, (%esp) # std::cout << obiekt1.a << std::endl;
.LEHB0:
    .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xf8,0x22
    .cfi_escape 0x10,0x6,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22
    call    _ZNSolsEi
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
.LEHE0:
    movl    $0, 24(%esp) # Here obiekt2.a = 0
    movl    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $_ZSt4cout, (%esp) # std::cout << obiekt2.a << std::endl;
.LEHB1:
    call    _ZNSolsEi
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
.LEHE1:
    movl    $0, %ebx
    leal    24(%esp), %eax
    movl    %eax, (%esp)
    call    _ZN11KlasaNiePODD1Ev
    leal    28(%esp), %eax
    movl    %eax, (%esp)
    call    _ZN11KlasaNiePODD1Ev
    movl    %ebx, %eax
    addl    $40, %esp
    popl    %ebx
    popl    %esi
    movl    %ebp, %esp
    popl    %ebp
    ret

Upvotes: 1

Views: 330

Answers (3)

PlasmaHH
PlasmaHH

Reputation: 16046

ISO 14882:2011(e) 8.5.1 :

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equalinitializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

As such, your class is an aggregate.

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

will invoke aggregate and finally value initialization, causing the int to be zero intialized.

Add

KlasaNiePOD(){}

to your class definition, and you will see that the setting to 0 will vanish (as this will make it not an aggregate anymore).

Upvotes: 1

James Kanze
James Kanze

Reputation: 153977

The standard defines several different types of initialization, depending on context. Zero-initialization sets all of the members to 0 (converted to the appropriate type, so pointers will be set to a null pointer value, even if the null pointer isn't all zero bits); no constructor is called. Default-initialization calls the default constructor, which be default doesn't do anything. Value-initialization calls the default constructor if a user defined constructor is present, but does zero-initialization, followed by the default constructor, if there is no user defined constructor. An object whose initializer is simply () (an empty list) is value-initialized. An object with static lifetime is zero-initialized before program start (always); if it has a non-trivial constructor, its constructor will be called sometime later (but before entering main). All other objects defined with no initializer are default-initialized.

In your code, obiekt1 is default-initialized; in this case, a no-op (leaving the members uninitialized). obiekt2 is initialized by copy of a value-initialized temporary; the value-initialization sets a to 0. (The actual copy may be optimized out, with the value-initialization taking place directly on the object.)

Upvotes: 3

Mike Seymour
Mike Seymour

Reputation: 254631

KlasaNiePOD obiekt1; // first case

This is default-initialised; since it doesn't have a default constructor, members with a fundamental type (which includes numeric types) are left uninitialised.

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

The temporary KlasaNiePOD() is value-initialised; since it doesn't have a default constructor, members with a numeric type are initialised to zero.

Upvotes: 5

Related Questions