views:

141

answers:

3

Can you help me is there definition in C++ standard that describes which one will be called constructor or assignment operator in this case:

#include <iostream>

using namespace std;

class CTest
{
public:

 CTest() : m_nTest(0)
 {
  cout << "Default constructor" << endl;
 }

 CTest(int a) : m_nTest(a)
 {
  cout << "Int constructor" << endl;
 }

 CTest(const CTest& obj)
 {
  m_nTest = obj.m_nTest;
  cout << "Copy constructor" << endl;
 }

 CTest& operator=(int rhs)
 {
  m_nTest = rhs;
  cout << "Assignment" << endl;
  return *this;
 }

protected:
 int m_nTest;
};

int _tmain(int argc, _TCHAR* argv[])
{
 CTest b = 5;

 return 0;
}

Or is it just a matter of compiler optimization?

+7  A: 

It’s always the default constructor taking an int that’s called in this case. This is called an implicit conversion and is semantically equivalent to the following code:

CTest b(5);

The assignment operator is never invoked in an initialization. Consider the following case:

CTest b = CTest(5);

Here, we call the constructor (taking an int) explicitly and then assign the result to b. But once again, no assignment operator is ever called. Strictly speaking, both cases would call the copy constructor after creating an object of type CTest. But in fact, the standard actively encourages compilers to optimize the copy constructor call here (§12.8/15) – in practice, modern C++ compilers won’t emit a copycon call here.

Konrad Rudolph
+1, but I would try to avoid 'default' in the sentence 'default constructor taking an int'. I think it will be clearer to just say 'the int constructor' or 'the constructor taking an int'. Default has an specific meaning (no-argument) in the standard.
David Rodríguez - dribeas
+6  A: 

What is happening here depends a bit on your compiler. It could create a temporary object using the int constructor and then copy construct b from that temporary. It will most likely elide the copy constructor call however. In neither case will the assignment operator be used.

anon
Can there be any difference between "CTest b(5)" and "CTest b = 5" depending on compiler?
ju
@ju Yes, that's what we are saying. The first will not use the copy constructor, the second might.
anon
Can you tell me why in the second case, compiler can decide to create temporary CTest object and call copy constructor at all? My theory was that by standard this 2 cases are absolutely equal :(
ju
@ju Bottom line - because the C++ Standard says it can - I'm afraid your theory is wrong. The copy constructor (which is what the Ctest b = 3 implies) requires an object of type CTest, but you are giving it an int, so the compiler can if it wishes construct a temporary using the other constructor, and some older compilers will do exactly that.
anon
AFAIK, the answer given by Konrad is correct. A compiler that constructs a temporary and then calls the copy constructor here does not conform to the standard.
Axel
@Axel: Konrad didn't say that...
visitor
@Axel: to expand a bit, Konrad cited that the Standard encourages compiler to optimize. "encourages" is different from "mandates".
Matthieu M.
+3  A: 

CTest b = 5; is an exact equivalent of CTest b(CTest(5)); Two constructors are involved: one taking an int (implicitly converting from integer 5), and the copy constructor. The assignment operator is in no way involved here.

The compiler may well optimize out the unnecessary copy, so the result would be as if you had typed CTest b(5). Therefore at runtime, both seeing "Copy constructor" printed (GCC with the -fno-elide-constructors option) or not (GCC by default) would be valid output of the program.

However, conceptually the compiler is required to check if an accessible and suitable copy constructor exists. The form CTest b = 5; would fail to compile if a) the copy constructor is private/protected (not accessible) or b) the copy constructor takes the argument by non-const reference (can't accept a temporary from CTest(5) - VC++ may accept it as a non-standard compiler extension, though).

The morale is: there is no easy way to tell where and how many times the copy constructor is called in a program by looking at the code. Copying can be often omitted, and therefore you should never rely on the side-effects of the copy constructor. If it does what it is supposed to do, then it shouldn't matter to you if the compiler eliminates some unnecessary copy constructor calls.

visitor