From: horst DOT kraemer AT snafu DOT de (Horst Kraemer) Newsgroups: comp.os.msdos.djgpp Subject: Re: no copy-ctor for temps Date: Sat, 02 Oct 1999 17:11:47 GMT Organization: [Posted via] Interactive Networx Lines: 115 Message-ID: <37f628ae.49715@news.snafu.de> References: <37f564ff DOT 3448616 AT newsserver DOT cc DOT monash DOT edu DOT au> NNTP-Posting-Host: n163-175.berlin.snafu.de X-Newsreader: Forte Free Agent 1.11/32.235 To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com On Sat, 02 Oct 1999 01:53:32 GMT, DavMac AT iname DOT com (Davin McCall) wrote: > On Fri, 01 Oct 1999 19:45:14 GMT, wemccaug AT prairienet DOT org (Wendy E. > McCaughrin) wrote: > > > The following example shows that 'gxx' will not invoke a copy-ctor > > for temporaries, only for variables. > > Are you saying that's bad? > > The code you point out as not calling the copy-ctor instantiates a > temporary instance of the class as a function parameter. The reason > that the copy-ctor is not called is because no copy operation is > performed - the temporary object is created directly on the stack > before the function is called. Or more precisely. For the call void TstCpy( Overflow ); // call by value TstCpy(Overflow(" I am a temporary\n")); the compiler doesn't generate a temporary at all which is copied to the actual parameter of TstCpy, although the formal description of the language describes this semantically. Instead it constructs the Overflow object directly in the place of the actual parameter of TstCpy. This behaviour is explicitly permissible according to the C++ Standard. Another example: complex c1(1,2); // 1 complex c2 = complex(1,2); // 2 Formally 1 is a direct-initialization c1 by the c'tor complex(double,double) and 2 is a copy-initialization (not a call to complex::operator= !!) of c2 via complex(const complex&) of a temporary constructed by complex(double,double). The compiler is allowed to elide the "useless" temporary and generate exactly the same code as for 3. This may have serious impacts if the copy-c'tor does something different than the "regualar" c'tor and the programmer expects it to be called. The programmer is obliged to implement a semantically correct copy c'tor which _does_ create a copy such that a program cannot tell it away from the original. He may not rely on side effects of the copy-c'tor which other c'tors don't produce because he is not sure if it is actually "called". A peciliarity: Say, your class defined a private copy-c'tor. private: Overflow(const Overflow&); Now TstCpy(Overflow("Huh ?")); wouldn't compile, although the compiler would not attempt to call the copy-c'tor because it elides the creation of the temporary as an optimization issue. This sounds illogical but it isn't. An optimizing compiler may not allow constructs which a non-optimizing compiler can't allow. The legality of a language construct cannot depend on the optimization level of a particular compiler. The IBM support thought differently some time ago: The question why the IBM C++ compiler does allow this construct with a private copy-c'tor got the answer: That's because our compiler optimizes away the call to the copy-c'tor... [full quote available] Many older compilers (like WATCOM and old Borland compilers) will compile this program, though: >------------------------------------------< #include #include struct X { X(int) {} private: X(const X&); }; void f(X) {} int main(int argc, char *argv[]) { f(1); // 1 X x(1); // OK X x=X(1); // 2 return 0; } >------------------------------------------< gcc 2.95 complains about 1 and 2. MS VC++ 6.0 complains about 2 but accepts 1... Regards Horst