views:

267

answers:

4

Hello everybody.

Here is the little code snippet:

class A
{
public:
    A(int value) : value_(value)
    {
     cout <<"Regular constructor" <<endl;
    }

    A(const A& other) : value_(other.value_) 
    {
     cout <<"Copy constructor" <<endl;
    }

private:
    int value_;
};
int main()
{
    A a = A(5);
}

I assumed that output would be "Regular Constructor" (for RHS) followed by "Copy constructor" for LHS. So I avoided this style and always declared variable of class as A a(5);. But to my surprise in the code above copy constructor is never called (Visual C++ 2008)

Does anybody know if this behavior is a result of compiler optimization, or some documented (and portable) feature of C++? Thanks.

+3  A: 

This is so called RVO.

To experiment a little try to comment out copy constructor.

Mykola Golubyev
RVO is Return value optimization. What return?
Alexey Malistov
Thanks. So by default I should not rely on it (as it may depend on the compiler)
BostonLogan
Return A(5). Instead it just put it straight in the a
Mykola Golubyev
It is better to implement your copy constructor to do "copy and construct". If you need copy constructor it should be in the sync with your regular constructor.
Mykola Golubyev
My fault. It is NRVO.
Mykola Golubyev
It is not NRVO. The only function involved is the constructor, and it has no named return value. NRVO is for when you have a normal function that declares a variable of the same type as its return type, and then it returns that variable. The compiler is allowed to construct the returned variable directly in the location that the caller would use for the return value. Ordinary copy-constructor elision, as in Logan's question, is *called* RVO, even without an explicit return. Both RVO and NRVO are described in the same paragraph of the standard (§12.8/15).
Rob Kennedy
Thanks. Probably I was confused with the section in the MSDN which advised to use 'copy constructor' for check NRVO presence in the compiler.
Mykola Golubyev
-1 This is wrong answer.
big-z
Realized mistake about NRVO. Changed back.
Mykola Golubyev
+1 - as the answer is correct but I would change this to "copy elision", with a possible reference to RVO, NRVO etc. @Rob: the standard doesn't ever use the term "Return Value Optimisation". At least according to wikipedia, RVO is considered as a type of copy elision rather than being an alias of it (http://en.wikipedia.org/wiki/Return_value_optimization).
Richard Corden
+7  A: 

From another comment: "So by default I should not rely on it (as it may depend on the compiler)"

No, it does not depend on the compiler, practically anyway. Any compiler worth a grain of sand won't waste time constructing an A, then copying it over.

In the standard it explicitly says that it is completely acceptable for T = x; to be equivalent to saying T(x);. (§12.8.15, pg. 211) Doing this with T(T(x)) is obviously redundant, so it removes the inner T.

To get the desired behavior, you'd force the compiler to default construct the first A:

A a;
// A is now a fully constructed object,
// so it can't call constructors again:
a = A(5);
GMan
Thanks GMan, I never use this syntax anyway. Just something to remember. Oh, just found on msdn: C++ standard allows the elision of the copy constructor (see section 12.8. Copying class objects, paragraph 15)
BostonLogan
Thanks, I see it now. It's a bit much to quote in an answer, so I'll just refer it by number.
GMan
It depends on compiler. Standard allows different behavior, see my answer.
Kirill V. Lyadvinsky
+3  A: 

Here you have copy-initialization of a from temporary A(5). Implementation allowed to skip calling copy constructor here according to C++ Standard 12.2/2.

Kirill V. Lyadvinsky
I don't think that's correct. The example in 12.2.2 involves a temporary being passed to a function before constructing the local object.
Kristo
A: 
A a = A(5);

This line is equivalent to

A a(5);

Despite its function-style appearance, the first line simply constructs a with the argument 5. No copying or temporaries are involved. From the C++ standard, section 12.1.11:

A functional notation type conversion (5.2.3) can be used to create new objects of its type. [ Note: The syntax looks like an explicit call of the constructor. —end note ]

Kristo