Daniel Harms
Daniel Harms

Reputation: 1208

Is the copy constructor, assignment operator, or both used here?

I have this snippet of code:

CFoo::CFoo()
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
    m_CBar = CBar(15);
}

When the instance of CBar is constructed on the right hand side of the third line of CFoo's constructor, is the copy constructor invoked to move it to m_CBar, or is only the assignment operator invoked by the compiler?

Upvotes: 0

Views: 95

Answers (3)

T.C.
T.C.

Reputation: 137310

Any class member that's not explicitly initialized in the constructor's member initializer list is default-initialized before the constructor's body is entered. For members of class type, that means default-constructed:

CFoo::CFoo()
// : m_CBar()         <--------- The constructor behaves as if you wrote this*
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
    m_CBar = CBar(15);
}

Thus, at m_CBar = CBar(15);, you are assigning a temporary instance of CBar, constructed with CBar(15), to m_CBar, which invokes the assignment operator.

It's usually better to construct m_CBar in the member initializer list:

CFoo::CFoo()
 : m_CBar(15)    // Directly constructs m_CBar, passing 15 to the CBar constructor
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
}

*: m_CBar() actually value-initializes m_CBar, which does the same thing as default-initialization in cases where, like here, m_CBar is of class type with a user provided constructor. In cases involving scalar types or classes with no user-supplied constructor, value-initialization will cause a zero-initialization (followed by invocation of any nontrivial implicit default constructor for something of non-union class type) to take place, while default-initialization does not cause a zero-initialization. You can find all the fun details with the definitions of all three kinds of initialization (zero, default, and value) in §8.5[dcl.init] of the C++11 standard.

C++14 made some changes to these rules, which plug some holes in certain edge cases. The most important change though is that objects with an explicitly defaulted default constructor are now always treated the same way as objects with an implicitly defined default constructor (and hence always first zero-initialized before the default constructor, if nontrivial, is invoked), regardless of whether it also has other user-provided constructors.

Upvotes: 5

Deduplicator
Deduplicator

Reputation: 45654

Taking your snippet apart:

CFoo::CFoo()
{
    InitializeCriticalSection( &m_CriticalSection );

m_CriticalSection was default-initialized (i.e. not initialized, as it's a struct of primitive types without ctor)

    m_IsInitialized = FALSE;

Dito for m_IsInitialized

    m_CBar = CBar(15);

m_CBar was default initialized (default-ctor), then the temporary was constructed, then assigned, then the temporary destroyed.

}

What you should do to reduce work, use the ctor initializer list:

CFoo::CFoo() : m_IsInitialized(), m_CBar(15)
{
    InitializeCriticalSection( &m_CriticalSection );
}

In C++11 and later you could even put the initializers in the member declaration, and they will be used if not overridden by the ctor init list of the called ctor.

Btw: In a definition with initializer like this:

CBar a = 1;

Only the respective ctor for a is called.
If it is initialized with a temporary of the same type, the copy can (and will on any compiler worth using) ellided:

Cbar a = CBar(1);

Or:

CBar a = make_cbar(1,2,3);

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

You will see the constructor CBar(15) called first, and then you will see a call to the assignment operator (demo #1).

Note that if you make the assignment a part of a declaration, like this

CBar a = CBar(15);

there would very likely be only the constructor - not a constructor + an assignment (demo #2) call when optimization is on, due to copy elision.

Upvotes: 1

Related Questions