5

Possible Duplicate:
Why copy constructor is not called in this case?

Consider the sample program below:

#include <iostream>

using namespace std;

class sample
{
    private:
        int x;

    public:
        sample(int a=0) : x(a)
        {
            cout << "default ctor invoked\n";
        }

        sample(const sample& obj)
        {
            cout << "copy ctor invoked\n";
        }

};

int main()
{
    sample s2 = sample(20); //Line1
    sample s3 = 20; //Line2

    return 0;
}

In Line1, first the constructor of sample class is invoked explicitly with the argument 20. Then i expected the copy constructor to be invoked to initialize s2.

In Line2, first the constructor of sample class is invoked implicitly first with the argument 20. Here also i expected the copy constructor to be invoked to initialize s2.

In both cases, the copy constructor is not invoked? Why is this happening? I believe, there is something wrong with my understanding of the invocation of copy constructor. Could someone correct me where i am going wrong?

Community
  • 1
  • 1
nitin_cherian
  • 6,405
  • 21
  • 76
  • 127
  • This is expected - let me try and find a good example – Adrian Cornish Jan 10 '12 at 04:42
  • Calls to the copy constructor can be elided in some situations. – R. Martinho Fernandes Jan 10 '12 at 04:45
  • @R.MartinhoFernandes : Ya some situations. But s2 and s3 has to be initialized some way. How is it done without calling the copy ctor? – nitin_cherian Jan 10 '12 at 04:46
  • Because compiler can initialise it directly, so why should it create a superfluous copy? – Cat Plus Plus Jan 10 '12 at 04:47
  • If on GCC use `-fno-elide-constructors` or on MSVC use `/Od` to see the copy constructors. – Jesse Good Jan 10 '12 at 04:49
  • @CatPlusPlus: Because this violates the as-if rule (note that the copy-ctor does not initialise `x`). – bitmask Jan 10 '12 at 04:54
  • @BenVoigt, for Line1, that duplicate seems to be relevant, yes. But I suspect Line2 `sample s3 = 20;` might be more interesting, in this case, is "construct-with-int followed by copy-construct" optional or outright illegal. – Aaron McDaid Jan 10 '12 at 04:54
  • 1
    @AaronMcDaid: That syntax is called *copy-initialization* in the standard. It causes a conversion (one arg constructor) followed by copy constructor, but the copy constructor call may be elided (the accessibility test is still done). It's basically the same rule for both cases, except in Line1 the conversion is explicit, in Line2 the conversion is implicit. Both are copy-initialization. – Ben Voigt Jan 10 '12 at 04:56
  • @bitmask: Copy constructors are allowed to be removed if no copy is necessary (since they're assumed to contain only copy logic — if you abuse that, then well, you've got bigger problems than just copy elision). – Cat Plus Plus Jan 10 '12 at 04:59
  • Here's the question and answer I really want to get linked: http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy-initialization-and-direct-initializati – Ben Voigt Jan 10 '12 at 05:02
  • And here's another: http://stackoverflow.com/questions/6163040/strange-behavior-of-copy-initialization-doesnt-call-the-copy-constructor – Ben Voigt Jan 10 '12 at 05:03
  • Ben: Thanks for the valuable links – nitin_cherian Jan 10 '12 at 05:17
  • I am unable to understand that, why are you expecting the invokation of copy constructor? Both of the lines requires default constructor for initialization. – Taha Jan 10 '12 at 07:36
  • @TSF: It's quite natural to expect the invocation of copy ctor, because in both Line1 and Line2, you are trying to initialize an object from another object. But copy ctor is not getting called due to compiler optimization called `copy elision`. `Ben` has very valid points and links to support the conclusion which i have derived at. Kindly take a look – nitin_cherian Jan 10 '12 at 07:41
  • I would suggest you to go through this FAQ: http://www.parashift.com/c++-faq-lite/ctors.html – Taha Jan 10 '12 at 07:54

2 Answers2

8

This is expected. It's called copy elision.

Your expectation is correct, but they made an exception in C++ (for performance) which allows the compiler to treat your expression as direct initialization of one instance while bypassing the copy constructor.

justin
  • 104,054
  • 14
  • 179
  • 226
  • For the first instance yes, the compiler may decide to do copy elision or not to do so. But I think that in the second line, `sample s3 = 20;`, then compiler *must* just call the `int` constructor. I think I'm asking "is copy elision *optional* in both cases?" – Aaron McDaid Jan 10 '12 at 04:51
  • 1
    Neither one will work if the copy constructor is inaccessible (i.e. `private`) or deleted. So it isn't *exactly* treated as direct initialization. – Ben Voigt Jan 10 '12 at 04:59
  • they both require copy initialization. both are equivalent to `sample s(sample(20));`. you can prove this by compiling after making the copy ctor private. copy elision is never required. it is *allowed* by the standard for compiler optimizations. whether it is elided or not is up to your compiler(s). – justin Jan 10 '12 at 05:01
  • Aha. So both are fully equivalent, in that the elision is *optional*. But they're not quite the same as `sample s4(20)`, in which case it must just directly call the `int` constructor? – Aaron McDaid Jan 10 '12 at 05:46
0

in first line it does not invoke copy constructor because you do not copy an object. You are assigning one object to other. C++ provide default = operator which perform shallow copy. And this is invoked implicitly. The constructor is called for right hand object and default constructor is invoked for the left hand object. After that default = operator is invoked.

For line 2, it use constructor that takes int parameters that you define. It is actually converter constructor because it takes an integer and creates object of your class. Thats why c++ use this as a converter constructor and when you try to assign an integer to your object, c++ invokes inplicitly this converter constructor.

I hope this helps you to understand.

oldTimes
  • 259
  • 3
  • 4
  • 13
  • Cemal: Your explanation on Line1 is not correct i think. As i understood from the others who have given answers and comments, both Line1 and Line2 are copy initialization, but compiler optimizes it to direct-initialization by preventing to call the copy constructor. – nitin_cherian Jan 10 '12 at 07:31
  • 1
    Yes you have right. Generally it use copy constructor when you use = operator but i did not realize according to text the asker asked. As you said i did not think about compiler optimization and directly think. Thanks for your warning – oldTimes Jan 10 '12 at 07:34