Reputation: 13398
I am starting a new project in C++11, and just found out about the delete
keyword that lets you prevent accidental calling of copy constructors and so on. Is there a "recommended" set of deletions I can do globally to increase type safety, such as preventing signed to unsigned cast within expressions? Should I default to delete
ing all 5 operations that I can delete
in all my classes?
FYI, this program requires high performance (thats why I'm using C++, for the first time in years) and there are very few times I want to copy anything, so a copy is usually a bug, although not 100% of the time, so I'm interested in this specific case, as well as the general case for other programs. I could potentially delete
the copy constructor and add a separate method that copies the object for the rare time that I do need a copy. Would that be a good idea?
Upvotes: 4
Views: 268
Reputation: 171263
Is there a "recommended" set of deletions I can do globally to increase type safety, such as preventing signed to unsigned cast within expressions?
No. You certainly can't prevent integer conversions by deleting anything.
Should I default to deleteing all 5 operations that I can delete in all my classes?
No! A deleted destructor would make it impossible to destroy anything!
Also, deleting a move constructor rarely makes sense. If your type can be moved cheaply then allowing moves (e.g. when returning objects by value, or passing temporaries by value as function arguments) is usually a good thing, even if you don't want to allow copies. Artificially restricting users of the type from moving it when doing so is efficient is just annoying and doesn't provide any advantages.
You seem to be falling into the trap of seeing a feature is available and thinking you should use it. The following quote from The Old Man and the C seems relevant:
One final anecdote regarding the earlier story where someone used an int reference parameter. In discussing this paper, the programmer's comment was - "Well, the feature was in the language so I figured I should use it.". It is our belief that this is not a sufficient criteria for using a feature of C++. A feature should be used only when it can be demonstrated to be of benefit. A mountain is climbed "because it is there". The same should not hold true for C++ features. Their mere existence is not justification for use.
As for your final question:
I could potentially delete the copy constructor and add a separate method that copies the object for the rare time that I do need a copy. Would that be a good idea?
... maybe ... this might be a case where a deleted copy constructor can be demonstrated to be of benefit. But I would say generally no, don't do that, because it makes it difficult to store the object in containers, for example. It is better to just write your code carefully to avoid unwanted copies. If you're failing to do that and have demonstrated you really are making accidental copies, maybe reconsider deleting the copy constructor.
But you should not be deleting operations "by default" just because you've learnt about the feature. It should be much more common to use = default
rather than = delete
except for classes that model some atypical behaviour, such as unique-ownership of a resource.
Upvotes: 7
Reputation: 28241
Yes, this idea seems to be good. Declaring all the unwanted special methods with delete
will disable them, just like you want.
However, this was also possible before delete
was invented - boost::noncopyable
was used for that purpose before the release of c++11. Even with c++11, inheriting from boost::noncopyable
seems to be easier (less typing) than marking all the unwanted special members with = delete
.
In additon, since you mentioned "preventing signed to unsigned cast" - you should be aware that conversions between built-in types (like int
to unsigned
) are built-in and cannot be disabled. Rules for conversions that don't involve a user-defined type are the same in C and C++ (with a small number of exceptions), and cannot be changed. The best you can do is configure your compiler to "emit all warnings" and possibly "treat warnings as errors".
Upvotes: 1
Reputation: 331
In my experience, there are certain cases when deleting certain constructors or operators makes sense.
For instance, consider the unique_ptr
class. unique_ptr
's are used when one wants only one pointer to access some sort of data (perhaps in a multithreaded application), and thus it wouldn't make sense to have multiple unique_ptr
's floating around that all point to the same object.
To prevent unwanted copy assignments, the following is included by default in the unique_ptr
class:
unique_ptr& operator= (const unique_ptr&) = delete;
That's one instance of when it would make sense to remove an operator from a class. I would say it's very much so a judgment call. My general rule is to ask myself, "is there absolutely no scenario in which the client of the class should be using x operator or y constructor?" If you then decide that x or y should in fact never (or perhaps only rarely) be used, then, in my opinion, it might make sense to go ahead and delete said operator/constructor.
Upvotes: 5