Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
511 views
in Technique[技术] by (71.8m points)

c++ - Default move constructor/assignment and deleted copy constructor/assignment

According to the standard,

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

— X does not have a user-declared copy constructor,

— X does not have a user-declared copy assignment operator,

— X does not have a user-declared move assignment operator, and

— X does not have a user-declared destructor.

Now the following fails to compile

# include <utility>

class Foo
{
public:
  Foo() = default;
  Foo(Foo const &) = delete;
};

int main()
{
  Foo f;
  Foo g(std::move(f)); // compilation fails here
  return 0;
}

So it seems that a deleted function is considered as user-defined, which makes sense (it is not its default implementation). However, in that particular case, how would deleted copy construtor/assignment mess default move constructor/assignment?

I think this question has practical importance because manual generation and esp. maintenance of such default functions is error prone, while at the same time, the (righteous) increase of the use of classes such as std::unique_ptr as class members made non-copyable classes much more common beasts than they used to be.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

user-declared means either either user-provided (defined by the user), explicitly defaulted (= default) or explicitly deleted (= delete) in contrast with implicitly defaulted / deleted (such as your move constructor).

So in your case, yes the move constructor is implicitly deleted because the copy-constructor is explicitly deleted (and thus user-declared).

However, in that particular case, how would deleted copy constructor/assignment mess default move constructor/assignment?

It would not, but the standard does not make the difference between this case and a complicated one.

The shortest answer is that having an implicitly defined move-constructor with an explicitly deleted copy-constructor might be dangerous in some cases, the same when you have a user-defined destructor and no user-defined copy-constructor (see rule of three/five/zero). Now, you can argue that a user-defined destructor does not delete the copy-constructor, but this is simply a flaw in the language which cannot be removed because it would break a lot of old (bad) program. To quote Bjarne Stroustrup:

In an ideal world, I think we would decide on “no generation” as the default and provide a really simple notation for “give me all the usual operations.” [...] Also, a “no default operations” policy leads to compile time errors (which we should have an easy way to fix), whereas a generate operations by default policy leads to problems that cannot be detected until run time.

You can read more about this in N3174=10-0164.

Note that most people follow the rule of three/five/zero, and in my opinion you should. By implicitly deleting the default move-constructor, the standard is "protecting" you from mistakes and should have protected you a long time before by deleting copy-constructor in some cases (see Bjarne's paper).

Further reading if you are interested:

I think this question has practical importance because manual generation and esp. maintenance of such default functions is error prone, while at the same time, the (righteous) increase of the use of classes such as std::unique_ptr as class members made non-copyable classes much more common beasts than they used to be.

Marking the move constructor as explicitly defaulted will solve this problem:

class Foo {
public:
  Foo() = default;
  Foo(Foo const &) = delete;
  Foo(Foo&&) = default;
};

You get a non-copyable object with a default move constructor, and in my opinion these explicit declarations are better than implicit ones (e.g. by only declaring the move constructor as default without deleting the copy-constructor).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...