Which is the difference between declaring a constr

2019-02-12 01:22发布

问题:

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);
}

回答1:

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...)



回答2:

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).



回答3:

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.



回答4:

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.



回答5:

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.



回答6:

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.



回答7:

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&);