5

I'm really confused.... does Type t = Type() call the copy constructor or no?

I'm asking because when I try:

#include <iostream>

class Test
{
public:
    Test(Test const &) { std::cout << "hello"; }
    Test() { }
};

int main()
{
    Test t = Test();
    return 0;
}

nothing is output, but when I change it to

#include <iostream>

class Test
{
    Test(Test const &) { std::cout << "hello"; }
public:
    Test() { }
};

int main()
{
    Test t = Test();
    return 0;
}

I get:

error C2248: 'Test::Test' : cannot access private member declared in class 'Test'

which doesn't make sense (especially since this is a debug build).

Update:

Even this compiles!

struct Test
{
    Test(Test &&) = delete;
    Test(Test const &) = delete;
    Test() { }
};

int main()
{
    Test t = Test();
    return 0;
}

So is a copy/move constructor necessary or no?

Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • Side effects are allowed to be ignored in copy elision. It still needs to be accessible, though. – chris Nov 23 '13 at 04:05
  • @chris: Are you sure copy elision is happening here? This is a debug build... – user541686 Nov 23 '13 at 04:06
  • You would think the move constructor would be a possibility, but seeing as how it's failing when it can't call the copy constructor, it's either only using that or there's a rule I'm forgetting. – chris Nov 23 '13 at 04:10
  • @chris: I totally forgot about the move constructor. I think the copy ctor is suppressing it, because the same exact thing happens when I replace `Test const &` with `Test &&`. Same mystery as before: does it require a move constructor? – user541686 Nov 23 '13 at 04:13
  • If they are both there as public, Both those constructors will be called for that one initialization. – Hanky Panky Nov 23 '13 at 04:16
  • According to @chris, I think this post explains similar thing: http://stackoverflow.com/questions/8890528/copy-constructor-elision – gongzhitaao Nov 23 '13 at 04:17
  • And here is the way to solve it: http://stackoverflow.com/questions/7779827/why-is-copy-constructor-not-being-called-in-this-code?rq=1, i.e. `-fno-elide-constructors` – gongzhitaao Nov 23 '13 at 04:19
  • I find it really interesting that deleting something in addition to the copy constructor makes it work. – chris Nov 23 '13 at 04:23
  • @Mehrdad This DOSE NOT COMPILE. `g++ 4.8` – gongzhitaao Nov 23 '13 at 04:24
  • @gongzhitaao: Sorry just realized I said `class` instead of `struct` on the last one... – user541686 Nov 23 '13 at 04:26
  • @Mehrdad still not compile. – gongzhitaao Nov 23 '13 at 04:27
  • @gongzhitaao: Ooh... is it a compiler bug then? – user541686 Nov 23 '13 at 04:27
  • tested with `g++ tmp.cpp -std=c++11` with `g++ 4.8` on ubuntu. And please see my previous reference and try `-fno-elide-constructors` with your original question. – gongzhitaao Nov 23 '13 at 04:28
  • @gongzhitaao: Er I know you tested with g++. I mean is it a Visual C++ bug then? – user541686 Nov 23 '13 at 04:29
  • @Mehrdad I don't know then:P I just test. But it seems that chris is right about the elision. – gongzhitaao Nov 23 '13 at 04:31
  • @Mehrdad, I suspected it was a compiler bug when writing my last comment. In fact, it does not compile on the MSVC12 CTP, while it does on the normal MSVC12. – chris Nov 23 '13 at 04:57
  • @chris: Interesting, it's a bug then, thanks. – user541686 Nov 23 '13 at 05:23

1 Answers1

3

From wikipedia:

In C++ computer programming, copy elision refers to a compiler optimization technique that eliminates unnecessary copying of objects. The C++ language standard generally allows implementations to perform any optimization, provided the resulting program's observable behavior is the same as if, i.e. pretending, the program was executed exactly as mandated by the standard.

The standard also describes a few situations where copying can be eliminated even if this would alter the program's behavior, the most common being the return value optimization. Another widely implemented optimization, described in the C++ standard, is when a temporary object of class type is copied to an object of the same type.[1] As a result, copy-initialization is usually equivalent to direct-initialization in terms of performance, but not in semantics; copy-initialization still requires an accessible copy constructor.[2] The optimization can not be applied to a temporary object that has been bound to a reference.

You are doing a copy construction, but the standard allows it to be converted to a direct initialization, and that is being done regardless of debug turned off, that's why the print isnt reached..

But, because it "should" be a copy construction, you do need access to one, which is why the second code doesnt work.

RichardPlunkett
  • 2,998
  • 14
  • 14
  • Tough question: why does this work, then? `struct Test { Test(Test const &&) = delete; Test(Test &&) = delete; Test() { } };` `int main() { Test t = Test(); return 0; }` – user541686 Nov 23 '13 at 04:16
  • that give me compile errors: error: use of deleted function 'Test::Test(Test&&)' – RichardPlunkett Nov 23 '13 at 05:04