Jump to content
  • Advertisement
Sign in to follow this  
crocomire

[C++] Copy constructor optimization

This topic is 3759 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The following code compiles without errors under Visual Studio 2005
class NoCopy
{
private:
	NoCopy(const NoCopy&);

protected:
	NoCopy() {}
	~NoCopy() {}
};


class Foo : private NoCopy
{
public:
	Foo(int) {}
	~Foo() {}
};

int main()
{
	Foo f(Foo(42));
}



Is the compiler allowed to optimize away the call to the copy constructor while calling the copy constructor is illegal?

Share this post


Link to post
Share on other sites
Advertisement
It shouldn't. I tested it under Borland Dev Studio 2006 and it outputs an error:
[C++ Error] Unit1.cpp(21): E2285 Could not find a match for 'Foo::Foo(Foo)'


VS 2008 doesn't output any errors.

Share this post


Link to post
Share on other sites
Because you did not specify a copy constructor for Foo, Foo has an implicit public copy constructor which is called. This copy constructor has to call NoCopy's copy constructor, respectively, which you declared private. So, no... the compiler shouldn't allow that.

Private copy constructor is something I've used in the past with gcc too, and I'm quite sure it worked as intended (i.e. it bailed out).

Share this post


Link to post
Share on other sites
Quote:
Original post by samoth
Because you did not specify a copy constructor for Foo, Foo has an implicit public copy constructor which is called. This copy constructor has to call NoCopy's copy constructor, respectively, which you declared private. So, no... the compiler shouldn't allow that.


But if I did specify a public copy constructor for Foo, the compiler would be allowed to optimize away the call to the copy constructor. So the question remains why the optimization isn't allowed in my example.

Share this post


Link to post
Share on other sites
I don't think the syntactic correctness of code should depend on compiler-specific optimizations.

Your attempt to use a private copy should be an error, even if the compiler would be later able to remove the copy altogether.

Share this post


Link to post
Share on other sites
I think the compiler is allowed to do it. The relevant section of the standard is:


When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):

— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value

— when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy

Share this post


Link to post
Share on other sites
In the following code the compiler is allowed by the standard to optimize away the call to the copy constructor. The optimization is not just a compiler specific optimization. Note that applying the optimization results in different behaviour.

#include <iostream>

class Foo
{
public:
Foo(const Foo&) { std::cout << "Foo(const Foo&)" << std::endl; }
Foo(int) { std::cout << "Foo(int)" << std::endl; }
~Foo() {}
};

int main()
{
Foo f(Foo(42));
}


So why isn't the compiler allowed to do the same optimization in my first example?

Share this post


Link to post
Share on other sites
Quote:
Original post by crocomire
So why isn't the compiler allowed to do the same optimization in my first example?



I think it is, which is why it compiles. :)

Share this post


Link to post
Share on other sites
I tried my example with the online Comeau C/C++ compiler:

Your Comeau C/C++ test results are as follows:

Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 11: error: "NoCopy::NoCopy(const NoCopy &)" (declared at line
4) is inaccessible
class Foo : private NoCopy
^
detected during implicit generation of "Foo::Foo(const Foo &)" at
line 20

1 error detected in the compilation of "ComeauTest.c".

In strict mode, with -tused, Compile failed

Share this post


Link to post
Share on other sites
Quote:
Original post by crocomire
But if I did specify a public copy constructor for Foo, the compiler would be allowed to optimize away the call to the copy constructor.
Yes, that's right, if your constructor doesn't initialize the base class, such as in:
Foo(const Foo&) {}

However, a "correct" copy constructor the way the compiler implements it would call the base constructor(s), somewhat like this:
Foo(const Foo&) : NoCopy() {}

Of course, NoCopy doesn't have any data members, and it's not meant to actually do anything, so it is silly to try to initialize something. However, that's because you know what's intended, the compiler doesn't know, to start with. The compiler can't just assume that it doesn't matter whether or not it initializes something just because it feels like it.

In the end, any decent compiler would finally decide that the constructor is useless and eliminate it, but access checking has to occur before any optimizations take place, because the first thing a compiler has to make sure is that a program is valid.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!