Copy constructor is not called for copy-initialization or optimized?
Asked Answered
F

2

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
}
Farfamed answered 9/1, 2011 at 14:7 Comment(1)
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?Verso
H
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?

Harmless answered 9/1, 2011 at 14:57 Comment(4)
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"));?Housewares
@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.Harmless
Case 1 does seem very similar to std::string str = "Copy Initialization";Farfamed
@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.Harmless
M
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.

Mol answered 9/1, 2011 at 14:16 Comment(6)
@ Prasoon There was no such const char [20] to T on a c++0x compiler because an implicit type conversion was made.Farfamed
@Prason: I really doubt it, please try to make sure on an actual c++0x compiler :)Farfamed
@Dave18: exactly what's different in C++0x from C++03, to allow this without the conversion to std::string being explicit?Harmless
@Steve There wouldn't be any but just in case I'm on MSVC++ 2010.Farfamed
@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.Electrotherapeutics
@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.Harmless

© 2022 - 2024 — McMap. All rights reserved.