Which is the difference between declaring a constructor private and =delete? - c++

For example, I want to declare a class but I want the client to not be able to use the copy constructor (or copy assignment operator)
Both of the following two does not allow the use of the copy constructor:
1.
class Track
{
public:
Track(){};
~Track(){};
private:
Track(const Track&){};
};
2.
class Track
{
public:
Track(){};
~Track(){};
Track(const Track&)=delete;
};
Is one of these ways "more correct" than the other or are equal? Is there any side-effect?
//Does not compile with both the above ways
int main()
{
Track l;
Track p(l);
}

Making it private is the "old" way of doing it. The constructor still exists, but it is private, and can only be invoked from within another class member function.
= delete deletes the constructor. It is not generated by the compiler, and it simply will not exist.
So most likely, = delete is what you want. (although with the caveat that not all compilers support this syntax yet, so if portability is a concern...)

Declaring a copy constructor private still allows member functions of the Track class to copy-construct instances of that class, while making it deleted simply forbids copy-constructing that object.
In C++11, deleting a copy constructor is the right way to express the fact that a class is non-copyable (unless of course it makes sense for you to let member functions of Track, or friends of Track, to copy-construct Track objects).

Making a constructor private was basically a "hack" in the old C++, since it was the only way to prevent users from using them. The ability to delete special member functions was only introduced in C++11, and it's the better and more idiomatic way to say that a class cannot be copied. since it is explicit about the intention.
Private constructors have other uses other than forbidding their use entirely (e.g. they may be called by static class member functions). So just making a constructor private doesn't communicate the intention very well, and the resulting error is not very clear, either.

Your first solution conveys to the reader that the copy-constructor is private and is not to be used.
Your second solution is only valid in C++11. Because of this, I'd say the more portable and readable implementation would be your first, using the private-property.

In the first case, you are essentially declaring a private copy constructor and then not providing any implementation. By declaring them private, non-members cannot copy it.
In the second case, the syntax forbids a copy being made. This is C++ native.
The major difference as a programmer is readability and understanding the code. The first case is redundant, why declare the copy constructor, make it private, and not implement it. The client has to infer a lot here.
You can just use "= delete" and clearly imply what you're trying to do.

Your first approach doesn't prevent the class itself from copying itself. The traditional way to solve this is to declare the copy-constructor private and to leave it unimplemented.
An issue with that, however, is that the intent might not be obvious. Someone reading the code might not understand why an orphaned declaration exists and might mistakenly remove it. Comments can help, as would privately inheriting from boost::noncopyable if Boost is available to you.
The second approach makes the intent obvious and is what you should prefer if you can use C++11.

If you are on C++11, use delete. The reason is that it makes the call explicit and the intent clear. You could still accidentally use a private constructor (e.g. in a restricted set of scopes), but the compiler will forbid you from ever using a deleted constructor.
One issue of the private constructor is that the class and friends can still use it -- this results not in access errors but link errors, which can be hard to trace back to the callsite.
If your necessary toolchains do not support deleted constructors (= delete), you should not define it (as seen in your question) -- only declare it and leave it undefined, e.g.: private: \n Track(const Track&);

Related

Does access control matter for deleted constructors?

Is there a difference in behavior between whether an explicitly deleted constructor is public, protected or private?
For example, a non copyable class would have a deleted copy constructor (and deleted copy assignment). The constructor would not be available to neither subclasses (or friends) nor to outside users of the class, because it doesn't exist, regardless of its access control.
The only difference I see would be in what manner different scopes would see that the copy constructor doesn't exist - whether it is just not there (as far as that scope knows) or it is explicitly deleted.
Now, it might be beneficial to have the best formal interface for the class - that is, if everyone should know that the class is non-copyable, it should be publicly deleted. Compiler error messages might also be more informative. But other than that - would there be any actual observable difference in the class behavior? That is, something one could do with a class which has its deleted constructor with access X which he couldn't do if that constructor had access Y?
Since it's overload resolution that makes the program ill-formed in this case, and not access specifiers (which are checked later), there is no difference in outcome. The compiler will always complain that a deleted function was picked.
But since the idiom before C++11 was "declare but not define a private copy c'tor to disable copying", I would consider it going along with the same idiom, and therefore favorable. You are using the "old slang" with some new language to describe the same thing, except better.

copy-swap idom : what if I change the class members?

I have a class
class MyClass
{
public :
int a;
int b;
}
For using the copy-swap idiom I then create the function
void MyClass::swap(MyClass& other)
{
std::swap(a,other.a);
std::swap(b,other.b);
}
If, later, I change my class and remove the member a, then the compiler will complain in the swap function, and that's fine.
But if I add a new member, my swap function is not correct anymore. What can I do in order to not forget adding the new member to the swap function ?
The problem is that your answer is not the copy and swap idiom. The actual copy and swap idiom is to write the copy constructor, and move operations for the class. The latter will give you an efficient swap operation via std::swap. Then you write your copy assignment by calling your class copy constructor to create a local copy. Then swap *this with the temporary. You don't do it member by member.
The best way to not forget is to just not write any of the special member functions, and have the compiler generate them for you. This is called the rule of zero. Most classes should not need to write these methods but simply choose members (or write them) such that the generated ones are correct. One of the reasons being no extra maintenance when adding a member.
Finally, if you are writing a resource management class and are writing these functions by hand, you don't necessarily want to use copy and swap. Copy and swap basically trades performance for strong exception safety. I've almost never made use of strong exception safety and in many domains it's just not practical to write things this way. So only use it if you need it.

When to use =default vs =delete

To my understand these semantics are used only with the copy constructor, moving constructor, copy assignment, moving assignment, and the destructor. Using = delete is for prohibiting the use of one of the functions, and that = default is used if you want to be explicit to the compiler on where to use the defaults for these functions.
What are the best practices when using these keywords while making a class? Or rather how do I keep mindful of these when developing a class?
For example, if I don't know whether I'll use one of these functions, is it better to prohibit it with delete or allow it and use default?
Good question.
Also important: Where to use = default and = delete.
I have somewhat controversial advice on this. It contradicts what we all learned (including myself) for C++98/03.
Start your class declaration with your data members:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
// ...
};
Then, as close as is practical, list all of the six special members that you want to explicitly declare, and in a predictable order (and don't list the ones you want the compiler to handle). The order I prefer is:
destructor // this tells me the very most important things about this class.
default constructor
copy constructor // I like to see my copy members together
copy assignment operator
move constructor // I like to see my move members together
move assignment operator
The reason for this order is:
Whatever special members you default, the reader is more likely to understand what the defaults do if they know what the data members are.
By listing the special members in a consistent place near the top, and in a consistent order, the reader is more likely to quickly realize which special members are not explicitly declared &dash; and thus either implicitly declared, or not do not exist at all.
Typically both copy members (constructor and assignment) are similar. Either both will
be implicitly defaulted or deleted, explicitly defaulted or deleted, or explicitly supplied. It is nice to confirm this in two lines of code right next to each other.
Typically both move members (constructor and assignment) are similar...
For example:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
public:
MyClass() = default;
MyClass(const MyClass& other);
MyClass& operator=(const MyClass& other);
MyClass(MyClass&&) = default;
MyClass& operator=(MyClass&&) = default;
// Other constructors...
// Other public member functions
// friend functions
// friend types
// private member functions
// ...
};
Knowing the convention, one can quickly see, without having to examine the entire class declaration that ~MyClass() is implicitly defaulted, and with the data members nearby, it is easy to see what that compiler-declared and supplied destructor does.
Next we can see that MyClass has an explicitly defaulted default constructor, and with the data members declared nearby, it is easy to see what that compiler-supplied default constructor does. It is also easy to see why the default constructor has been explicitly declared: Because we need a user-defined copy constructor, and that would inhibit a compiler-supplied default constructor if not explicitly defaulted.
Next we see that there is a user-supplied copy constructor and copy assignment operator. Why? Well, with the data members nearby, it is easy to speculate that perhaps a deep-copy of the unique_ptr ptr_ is needed. We can't know that for sure of course without inspecting the definition of the copy members. But even without having those definitions handy, we are already pretty well informed.
With user-declared copy members, move members would be implicitly not declared if we did nothing. But here we easily see (because everything is predictably grouped and ordered at the top of the MyClass declaration) that we have explicitly defaulted move members. And again, because the data members are nearby, we can immediately see what these compiler-supplied move members will do.
In summary, we don't yet have a clue exactly what MyClass does and what role it will play in this program. However even lacking that knowledge, we already know a great deal about MyClass.
We know MyClass:
Holds a uniquely owning pointer to some (probably polymorphic) OtherClass.
Holds a string serving as a name.
Holds a bunch of doubles severing as some kind of data.
Will properly destruct itself without leaking anything.
Will default construct itself with a null ptr_, empty name_ and data_.
Will copy itself, not positive exactly how, but there is a likely algorithm we can easily check elsewhere.
Will efficiently (and correctly) move itself by moving each of the three data members.
That's a lot to know within 10 or so lines of code. And we didn't have to go hunting through hundreds of lines of code that I'm sure are needed for a proper implementation of MyClass to learn all this: because it was all at the top and in a predictable order.
One might want to tweak this recipe say to place nested types prior to the data members so that the data members can be declared in terms of the nested types. However the spirit of this recommendation is to declare the private data members, and special members, both as close to the top as practical, and as close to each other as practical. This runs contrary to advice given in the past (probably even by myself), that private data members are an implementation detail, not important enough to be at the top of the class declaration.
But in hindsight (hindsight is always 20/20), private data members, even though being inaccessible to distant code (which is a good thing) do dictate and describe the fundamental behaviors of a type when any of its special members are compiler-supplied.
And knowing what the special members of a class do, is one of the most important aspects of understanding any type.
Is it destructible?
Is it default constructible?
Is it copyable?
Is it movable?
Does it have value semantics or reference semantics?
Every type has answers to these questions, and it is best to get these questions & answers out of the way ASAP. Then you can more easily concentrate on what makes this type different from every other type.
Also, using =default instead of a hand-rolled one keeps the POD nature of the class, as it is described here in detail: Default constructors and POD
You often see = default when you are trying to maintain the rule of 5 to ensure the special member functions behave as you intend them to, and so that the reader of the class can see that you did consider how you wanted that function to behave.
You can use = delete if you intent to make something non-copyable or non-movable, for example. Though I have also seen people delete an inherited function if they do not want that specific derived class to have that function, though I'm not a huge fan of that since it tends to point towards poor architecture/design.

For a static class (with private constructor) in C++, should I define a destructor?

I have a static class in C++, i.e. all members of this class are static.
Since I do not want the class to be instantiated ever, I make the constructor private.
I did not define a default copy assignment operator or copy constructor for this class, since this can never be instantiated. However, my static code analyzer tells me:
If you have declared a destructor because your class manages resources, you may want to declare a copy constructor and copy assignment operator too for the same reason.
-> Is it OK if I do not define a destructor for this class? Since it can never be created, it cannot be destroyed either, I suppose?
-> Is this a good practice? Anything wrong with my design?
Since I do not want the class to be instantiated ever, I make the constructor private.
If you have access to a C++11 compiler, you have a better option: you can explicitly delete the "gratuitous" constructor provided by the compiler. This should address the problem with the destructor, because the compiler would know that it is impossible to construct your class.
If you cannot use the deleted constructor feature, declaring a constructor private should be sufficient to prevent outside instantiations. The destructor is not necessary, because there is nothing to destruct.
Is this a good practice? Anything wrong with my design?
This practice is more common in languages where it is not possible to define free-standing functions/variables. C++, on the other hand, provides free-standing functions and variables. A combination of these two features with namespaces makes classes with only static members unnecessary: such class would be functionally equivalent to a namespace, but would not be idiomatic to C++.

Copying objects with only move semantics

Before anything else, let me take you all into the highway of my thoughts (to say it simply, I'm just imagining these things)
Suppose, I am using a third-party library class that uses move semantics (r-value references). Here is its definition:
class VeryHeavyObject {
VeryHeavyObject(const VeryHeavyObject& obj); // copy constructor
VeryHeavyObject& operator= (const VeryHeavyObject& obj); // copy operator
public:
VeryHeavyObject(); // constructor
VeryHeavyObject(VeryHeavyObject&& obj); // move constructor
VeryHeavyObject& operator= (VeryHeavyObject&& obj); // move operator
// ....
};
Apparently, the author's really concerned about the cost of copying of VeryHeavyObject and decided to force everything to be moved (More apparently, he doesn't know how to design classes with move semantics). But then, in some point of my code, I need to have a copy of VeryHeavyObject.
Well, the core question is:
How can I copy an object with only a move constructor and a move operator?
P.S.: I have tried but I can't really contact the author of the library (I think he's on vacation).
You cannot.
However, provided that you have sufficient access to its internals (getters and the like), then you can construct a clone by yourself.
A well defined interface, and we will assume that this is the case, some methods may not be available because the author wants to discourage certain uses for performance reasons. A well-known example is std::list, which does not include a [] operator because it has O(n) complexity compared with O(1) in other containers, such as std::vector.
In this case, the author of the library wants to discourage the use of copies because, as you state in your question, it is very costly. But this does not mean that it is impossible. If you really need to do it, you can probably write your own Clone() function that takes data from the original VeryHeavyObject as appropriate, constructs a new one with these data and returns it using std::move. Since we haven't got the interface for VeryHeavyObject we cannot try to do it, but I'm sure you can.
It might not be possible.
The class has declared the copies private, but we can't see whether the functions are ever defined. You seem to assume that the class has a copy operation that it's hiding away from you to stop you doing something slow, but that might not be the case. Some objects simply cannot be copied. For examples, consider streams.
You wouldn't expect privately-declared-but-not-defined functions in C++11, but there's no law against it. Anyway even if there is an implemented private copy function, it's probably private for a reason (maybe it can only be used under certain controlled circumstances: the class internals know how to use it safely and you don't). So if there's no public copy, then as far as this class's API is concerned it cannot be copied.
Perhaps the class has enough public accessors, that you can interrogate it for the state you need, and construct a new object that matches it. If so then you could reasonably complain to the author of the class that it should be publicly copyable. If not then maybe it has state that can't be duplicated.
Anything that provides unique access to something (streams, drivers, locks) has a reason not to be copyable, because the original and the copy can't both provide unique access to the same thing. Admittedly dup means that even file descriptors don't physically provide unique access to something, let alone the streams that wrap them. But a stream has state involving buffered data not yet written, which means that copying them would introduce complexity that the class is designed to protect you from. So logically you normally use a stream as though it is the only way to access something.
If the copy assignment operator is implemented, then you might be able to hack a way to call it even though it's private. That won't work for the copy constructor, though, you can't take pointers to constructors. As a brutal hack you could #define private public before including its header: it's undefined behavior but it might work on the implementation you're using. Forking the third-party source would be better.
In general, it is not possible without modifying the class, because there might be private data that you cannot access. It might be possible if a shallow copy is sufficient, because then you should be able to do it with a memccpy. (Note that if the class does not have any virtual members or pointers, shallow and deep copy are the same).