In C++, if copying an object is possible, but really expensive and usually a bad idea, should you still implement copying using a copy constructor?

  • A+
Category:Languages

I'm pretty new to C++, and I have a question regarding some C++ conventions regarding copying. I've googled around and haven't really been able to find good guidance on this, so I'm turning to you fine folks.

Let say you have an object that represents some resource that is technically copyable, but the copy is a expensive and almost always the wrong thing to do. Should you still implement a copy constructor for it? Or is it better to make a member function that is something like make_copy() (for those rare times when you DO want to copy the object).

For instance: lets say you have a class representing a texture stored in video memory. This resource is technically copyable: you can create a new handle for it and copy the memory (either through the CPU or using graphics library calls). But generally speaking, this is not something you really want to do very often. It's expensive, and it's usually the wrong thing to do, and is potentially very wasteful of memory. However, you could imagine corner cases where it would make sense: taking a screenshot and applying filters over it or something. Those cases would be rare, but they would exist.

The reason I'm hesitant making a copy constructor that does this this is that I feel like C++ is a bit too eager to copy stuff. Maybe it reflects the fact that I'm a bit new to the language, but since C++ will call the copy constructor in all sorts of situations where you might not mean for it to do so. Like:

void some_method(Texture t) {     ... }  Texture t(<arguments>); Texture t2 = t;        // calls copy constructor  some_method(t2);       // calls copy constructor 

I would much rather these two lines that calls copy constructors be compiler errors (because I feel like they're very easy mistakes to make) and if you want to actually make a copy, you need to be very explicit about it and use a dedicated member function.

Is there some standard practice around this? Some sage advice on when you should (and shouldn't) write copy constructors? Some Scott Meyers chapter I've missed? Or should I just do it whenever it's possible?

EDIT: to be clear about my example: obviously, you should pass the argument by reference, but my point was that this is a very easy mistake to make, just leaving out the ampersand. And if you do that, the compiler will happily replace a cheap pass-by-reference with a very expensive copy, and I would rather the compiler not do that. But I dunno, maybe this isn't a mistake people generally make in C++, and I'm being overly cautious?

 


Whether you want to use it is your call, but here is a pattern that is relatively light on syntax:

struct ExplicitCopy {      // Implement as usual     ExplicitCopy() = default;     ExplicitCopy(ExplicitCopy &&) = default;     ExplicitCopy &operator = (ExplicitCopy &&) = default;      // Copying happens with an ADL call to this function     friend ExplicitCopy copy(ExplicitCopy const &orig) {         return orig;     }  private:     // Copy operations are private and can't be called accidentally     ExplicitCopy(ExplicitCopy const &) = default;     ExplicitCopy &operator = (ExplicitCopy const &) = default; }; 

Then, trying to copy an instance will result in a compiler error from the call to a private constructor.

ExplicitCopy ec; ExplicitCopy ec2 = ec;       // Nope ExplicitCopy ec3(ec);        // Nope ExplicitCopy ec4 = copy(ec); // Yes 

Thanks to copy elision, there is no additional constructor call.

See it live on Coliru

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: