Reputation: 1208
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
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
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
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