1

If copy constructor is made private then in

Case 1: No error, the compiler doesn't care if the copy constructor was defined in class.

Case 2: Error, copy constructor is private and when it is made public, it is elided.

Does it directly optimizes the copy without being noticing that if the constructor was made private?

#include <string>
using std::string;

class T
{
    string s;
    T(const T &obj):s(obj.s){}
public:
    T(const string &str):s(str){}
};

int main()
{
    T a = ("Copy Initialization");     //Case: 1

    T b = T("Copy Initialization");    //Case: 2
}
cpx
  • 17,009
  • 20
  • 87
  • 142
  • In the `Case:1` you are not actually creating a temporary object of type `T`. How could you assign it `a` which is of type `T`? – Mahesh Jan 09 '11 at 14:17

2 Answers2

5

Case 2 comes under 12.8/31 in N3225:

A program is ill-formed if the copy/move constructor or the copy/move assignment operator for an object is implicitly odr-used and the special member function is not accessible.

Just because the copy ctor is elided doesn't mean it isn't odr-used. 3.2/2:

A member of a set of candidate functions is odr-used if it is selected by overload resolution when referred to from a potentially-evaluated expression. [Note: this covers calls to named functions (5.2.2), oper- ator overloading (Clause 13), user-defined conversions (12.3.2), allocation function for placement new (5.3.4), as well as non-default initialization (8.5). A copy constructor or move constructor is odr-used even if the call is actually elided by the implementation. —end note ]

Beware of course that MSVC is not fully C++0x-compliant, because (a) C++0x isn't a standard yet, and isn't finalized; and (b) MSVC hasn't implemented everything up to date anyway. But this stuff isn't substantially changed from C++03, so I'm fairly confident the explanation still holds.

Case 1 would come under this too, except that on the two C++03 compilers I've checked it doesn't get that far because there's no possible conversion from a string literal to T. I can't be bothered to check whether there are any additional conversion sequences allowed in C++0x, there could be a new clause anywhere :-)

It's still a mystery to me why MSVC allows case 1 ever, even with a public copy ctor. Does it allow it in strict C++03 mode?

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Are you sure. G++ and Comeau give errors for both. Perhaps the first line (if invoking string constructor explicitly) is equivalent of `T a = T(string("Copy Initialization"));`? – UncleBens Jan 09 '11 at 15:10
  • @UncleBens: Am I sure about what? The thing I originally said about case 1 was just completely wrong, don't know what I was thinking. g++ and Comeau reject case 1 because no conversion sequence exists (there's a hypothetical sequence with two implicit user-defined conversions, but that's disallowed), the copy ctor doesn't become relevant. Adding the explicit conversion to `string`, then it becomes relevant. – Steve Jessop Jan 09 '11 at 15:13
  • `Case 1` does seem very similar to `std::string str = "Copy Initialization"`; – cpx Jan 09 '11 at 15:22
  • 1
    @Dave18: the important difference being that `std::string` has a `const char*` constructor, and `T` doesn't. It wouldn't utterly surprise me if a vendor (MS in this case) had an extension to treat that conversion as if it were built-in, even though it's user-defined according to the standard. For "convenience", in the sense of convenience for people who only ever write code for that compiler with that extension enabled, so they can just give their classes a `string` constructor, and not also a `const char*` constructor. – Steve Jessop Jan 09 '11 at 15:24
2

Case 1: No error, the compiler doesn't care if the copy constructor was defined in class.

T a = ("Copy Initialization"); should give an error because there's no suitable constructor to convert from "const char [20]" to "T"

Did you mean T a = std::string("Copy Initialization"); ?

Does it directly optimizes the copy without being noticing that if the constructor was made private?

No it can't. Compilers usually perform syntactic and semantic analysis prior to the code optimization phase.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • @ Prasoon There was no such `const char [20]` to `T` on a c++0x compiler because an implicit type conversion was made. – cpx Jan 09 '11 at 14:23
  • @Prason: I really doubt it, please try to make sure on an actual c++0x compiler :) – cpx Jan 09 '11 at 14:28
  • 1
    @Dave18: exactly what's different in C++0x from C++03, to allow this without the conversion to `std::string` being explicit? – Steve Jessop Jan 09 '11 at 14:48
  • @Steve There wouldn't be any but just in case I'm on MSVC++ 2010. – cpx Jan 09 '11 at 14:51
  • 1
    @Dave18: There are two user-defined conversions needed for Case 1: First from string-literal (`const char [20]`) to `std::string` and then from `std::string` to `T`. Such a conversion sequence can not be deduced by the compiler, as it can/may use at most one user-defined conversion in a conversion sequence. – Bart van Ingen Schenau Jan 09 '11 at 14:52
  • @Dave18: if there are no relevant changes in the standard from C++03, then this is either a bug in MSVC, or you're using a non-pedantic mode that allows it. – Steve Jessop Jan 09 '11 at 15:01