为什么删除move constructor cause vector停止工作 [英] why does deleting move constructor cause vector to stop working

查看:191
本文介绍了为什么删除move constructor cause vector停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我禁止一个类中的移动构造函数,我不能再在一个向量中使用它:

If I inhibit the move constructor in a class, I can no longer use it in a vector:

class Foo
{
  public:
      Foo(int i) : i_(i) {}
      Foo(Foo&&) = delete;

      int i_;
};

int main()
{
    std::vector<Foo> foo;
    foo.push_back(Foo(1));
}

为什么会这样?

推荐答案

摘要

不要删除移动成员。

假设你的编译器完全符合C ++ 11,那么显式删除move构造函数也会隐式地声明

Assuming your compiler is completely C++11 conforming, then explicitly deleting the move constructor will also implicitly declare the following:

Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;

这是如果你声明一个移动构造函数(或移动赋值运算符),并且不声明复制成员,它们被隐式声明为已删除。所以你完整的Foo类如下:

That is if you declare a move constructor (or move assignment operator), and do not declare copy members, they are implicitly declared as deleted. So your complete class Foo is as if:

class Foo
{
  public:
      Foo(int i) : i_(i) {}
      Foo(Foo&&) = delete;
      Foo(const Foo&) = delete;             // implicitly declared
      Foo& operator=(const Foo&) = delete;  // implicitly declared

      int i_;
};

现在向量< Foo> :: push_back(Foo(1))要求 Foo MoveConstructible MoveConstructible 可以通过可访问的移动构造函数,甚至可访问的复制构造函数来满足。但 Foo 没有。要解决这个问题,您可以:

Now vector<Foo>::push_back(Foo(1)) requires that Foo be MoveConstructible. MoveConstructible could be satisfied by an accessible move constructor, or even by an accessible copy constructor. But Foo has neither. To fix you could:

class Foo
{
  public:
      Foo(int i) : i_(i) {}
      Foo(const Foo&) = default;
      Foo& operator=(const Foo&) = default;

      int i_;
};

默认复制成员并删除已删除的移动成员。

I.e. default the copy members and remove the deleted move member.

一般来说,明确删除移动成员并不是一个好主意。如果你想要一个类是可复制的,但不是可移动,只是声明完全一样,你会在C ++ 03:声明/定义你的副本成员。您可以让复制成员使用 = default 编译器生成,并且仍然被视为用户声明。并且不要声明移动成员。不存在的移动成员与删除的移动成员不同。

In general it is not a good idea to explicitly delete the move members. If you want a class to be copyable but not "movable", just declare exactly as you would in C++03: declare/define your copy members. You can let the copy members be compiler-generated with = default, and that still counts as a user-declaration. And don't declare move members. Move members that don't exist are not the same as deleted move members.

已删除的移动成员意味着您无法构造 Foo 从一个右值,即使复制构造函数将工作正常这样做。这很少是所需的意图。

Deleted move members mean you can not construct a copy of Foo from an rvalue, even if the copy constructor would have worked fine to do so. This is rarely the desired intent.

即使你希望你的类不能复制也不可移动,最好是删除复制成员,并保留移动成员未声明(意味着它们不会存在)。如果你正在审查代码(包括你自己的),并看到删除的移动成员,他们几乎肯定是不正确的,或在最好的多余和混乱。

Even if you want your class to not be copyable nor movable, it is better to just delete the copy members and leave the move members undeclared (meaning they won't exist). If you're ever reviewing code (including your own), and see deleted move members, they are almost certainly incorrect, or at the very best superfluous and confusing.

天有人会想出一个好的用例删除移动成员。但它将是一个罕见的用例。如果你在代码中看到这样的模式,你应该期望代码作者有一个很好的解释。否则,删除的移动成员可能只是不正确(最好是多余的)。但是在明亮的一面,这个错误将在编译时显示,而不是在运行时(如在你的例子中)。

Some day someone will come up with a good use case for deleted move members. But it will be a rare use case. If you see such a pattern in code, you should expect the code author to have a very good explanation. Otherwise, deleted move members are likely to just be incorrect (at best superfluous). But on the bright side this error will show itself at compile time, instead of at run time (as in your example).

这里是一个汇编图将隐式地做,当你显式声明任何特殊成员。

Here is a summary chart of what the compiler will implicitly do when you explicitly declare any of the special members. Those squares colored red represent deprecated behavior.

= default = delete 作为用户声明的

这里,如果您想查看完整的幻灯片。

Click here if you would like to view the full slide deck.

这篇关于为什么删除move constructor cause vector停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆