4

A colleague is cleaning up a couple of libraries. In doing so he's been reading API design for C++ and it talks about explicitly enabling or disabling copying in C++ classes. This is the same thing that Sutter and Alexandrescu say in their C++ Coding Standards.

He agrees that one should follow this advice, but what neither book seems to say are what are those guiding principles that tell when to enable or disable.

Any guidance one way or the other? Thanks!

John
  • 15,990
  • 10
  • 70
  • 110

5 Answers5

6

It depends on the role the classes play in the application. Unless the class represents a value, where identity isn't significant, you should ban copy and assignment. Similarly if the class is polymorphic. As a generally rule, if you're allocating objects of the class type dynamically, it shouldn't be copiable. And inversely, if the class is copiable, you shouldn't allocate instances of it dynamically. (But there are some exceptions, and it's not rare to allocate dynamically and avoid copying big objects, even when the semantics argue otherwise.)

If you're designing a low-level library, the choice is less clear. Something like std::vector can play many roles in an application; in most of them, copying wouldn't be appropriate, but banning copy would make it unusable in the few where it is appropriate.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • +1: I was thinking about DeadMG's answer, and I realized that most of the classes I write a appropriately non-copyable. The role they play in the system is such that this is what makes sense. OTOH, I will say that systems in which more classes are copyable are usually better designed. A non-copyable class isn't the same level of evil as a singleton, but to me it makes me wonder if there isn't a way to divide things up so more pieces are copyable. – Omnifarious Jun 23 '11 at 17:34
  • "if the class is polymorphic" - you could almost say, if the class is polymorphic then it *won't* be copyable (when used polymorphically), and you should therefore strongly consider banning users from *slicing* it. – Steve Jessop Jun 23 '11 at 17:35
  • @Steve Jessop: There's that too. Polymorphic classes should have a `clone` method and disable the copy constructor and assignment operator if they need to be copied. – Omnifarious Jun 23 '11 at 17:37
  • 1
    @Omnifarious It depends a lot on what you're doing. Classes that model something outside the program should never be copiable. Classes that represent individual values generally should be. Depending on your application, you may have more of one, or more of the other. There's nothing wrong with noncopiable classes (or singletons, for that matter), provided they correspond to what is needed. – James Kanze Jun 23 '11 at 17:47
  • @Omnifarous: indeed. Of course you may not need to disable the operators explicitly - if your polymorphic base classes are abstract then it's naturally impossible to slice. It might make perfect sense for leaf classes to be copyable, since you could occasionally have a class that can be useful both through its polymorphic interface (perhaps allocated dynamically) *and* as a value type (not allocated dynamically). Rare, though. – Steve Jessop Jun 23 '11 at 17:48
  • 1
    @Steve Jessop Whether you want to support cloning or not depends on the application; I've found cloning useful when you have transactions that need rolling back, but not otherwise. – James Kanze Jun 23 '11 at 17:55
  • 3
    @James Kanze: I have come to the conclusion that there is never a good excuse for a singleton. Seriously, never. But that's a debate for another place. :-) – Omnifarious Jun 23 '11 at 18:14
  • @James: the design concerns probably become almost circular - *if* you find yourself wanting to copy a polymorphic type via a reference-to-base (however rare that is), *then* you need clone. But, if you find yourself copying anything, that suggests you want it to have value semantics, which means you don't want to actually *use* that pointer-to-base and clone directly, you want to wrap it in some other class that holds the pointer, delegates method calls, and calls clone for you on copy, so the wrapper does have value semantics. So you still only copy value-things, not polymorphic-things. – Steve Jessop Jun 23 '11 at 18:28
  • "delegates method calls" - ahem, sorry, I have Python and C++ in my head simultaneously. Member function calls. – Steve Jessop Jun 23 '11 at 18:42
  • 1
    @Steve Exactly: the desire to copy suggests that value semantics might be more appropriate (or you've misunderstood the design). On the whole, value semantics and polymorphism don't work well together, although they can be implemented, using the letter-envelop idiom or something similar. As for cloning, I've usually used it in transaction management, where I'd clone an instance so that I could modify one copy, and keep the other in case of roll-back. But that's a special use of copy, not related to value semantics. – James Kanze Jun 24 '11 at 08:21
5

Classes which are non-copyable should be the exception, not the rule. Your class should be non-copyable if and only if you cannot retain value semantics while copying- for example, named mutexes, unique-ownership pointers. Else, your class should be copyable. Many C++ libraries depend on copyability, especially pre-C++0x where they cannot be movable.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    Your "if and only if" is a little too restrictive, IMO. If I have (say) an "Image" class that consumes several megabytes, I might well make it non-copyable (except maybe by calling a special function). Because even though the semantics allow you to make a copy, you almost certainly do not want to... Sometimes "value semantics" are just too expensive. – Nemo Jun 23 '11 at 17:37
  • 1
    @Nemo: in that case, I'd usually leave it to the user to figure out their own performance constraints. If they can figure out a way to use a really tiny image, or if they're using a gigantic image but they have all day, then they can copy it for all I care. Before C++0x there's also the NRVO issue - the class has to be *copyable* even in some situations where (on a half-decent compiler) it isn't actually *copied*. That said, if the thing isn't copyable but has a copy function, they can always stick their own wrapper around it if they need copy semantics, so your way certainly works. – Steve Jessop Jun 23 '11 at 17:42
  • @Steve: Yeah, it really depends on your environment, like how much competence you can expect from your co-workers... :-) – Nemo Jun 23 '11 at 17:49
  • @Nemo: Not being able to retain value semantics because of performance sounds like it falls quite clearly under "not being able to retain value semantics" to me. – Puppy Jun 23 '11 at 17:55
  • I guess I distinguish between "can" and "should". And performance is usually "should". Anyway I gave you an upvote. – Nemo Jun 23 '11 at 18:37
5

Contrary to DeadMG, I believe most classes should be non-copyable.

Here is what Stroustrup wrote in his "The Design and Evolution of C++" book:

"I personally consider it unfortunate that copy operations are defined by default and I prohibit copying of objects of many of my classes"

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
  • Ha ... I've gotten into the middle of discussions by invoking what Stroustrup said, but all in all that's not a bad thing? :) – John Jun 23 '11 at 18:14
  • Stroustrup has deployed some excellent weasel-wording there, is "many" more or less than "most"? Nobody knows! I think his view probably is that it's unfortunate *anything* is defined by default, but that's part of C compatibility. He doesn't say what *proportion* of classes are copyable, only that there's nothing particularly unusual about being non-copyable. Even if 99% of my classes were copyable, I'm still inclined to say it's better to be non-copyable *by default*, because a class with a default copy that's broken is >100 times worse than having to enable copying explicitly would be. – Steve Jessop Jun 23 '11 at 18:38
0

I think you should try to write as little code as possible to have the class doing what it is supposed to do. If no one is trying to copy the class and it is not going to be copied in the near future then do not add stuff like a copy constructor or assignment operator. Just make the class non copyable.

When someday you actually want to copy the class, then add things like the copy constructor. But until then having the class non copyable means less code to test and maintain.

rve
  • 5,897
  • 3
  • 40
  • 64
0

I sincerely believe that copy semantics should be provided automatically, or not at all.

However, badly written libraries may sometimes benefit from a manual copy constructor.

Note that the situation is very different in C++ (because copy semantics are usually required by the standard library !) than in C++0x, where my advice pretty much always applies.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197