【问题标题】:When should compiler generate move constructor?编译器何时应该生成移动构造函数?
【发布时间】:2012-10-21 21:59:30
【问题描述】:

我使用 VS11 并使用以下内容:

class ContextWrapper
{
public:

    ContextWrapper()
    {
    } //it should be defaulted I *guess* in order to have automatic move constructor ?
      // no support in VS11 for that now  

    Context* GetContext()
    {
        return this->context.get();
    }

    void SetContext(std::unique_ptr<Context> context)
    {
        this->context = std::move(context);
    }

    //ContextWrapper(ContextWrapper&& other):  context(std::move(other.context))
    //{
    //} // I would like this to be generated by the compiler

private:
    ContextWrapper(const ContextWrapper&);
    ContextWrapper& operator= (const ContextWrapper&);

    std::unique_ptr<Context> context;
};

我希望此类生成移动构造函数/赋值。我没有一个微不足道的构造函数的事实是我没有得到移动的原因吗?还是有其他因素影响?

【问题讨论】:

  • 未生成移动构造函数,因为您声明了复制构造函数。移除私有拷贝构造函数和拷贝赋值。
  • 添加一个不可复制的成员(比如unique_ptr)已经阻止了复制特殊成员的生成,所以无论如何都不需要手动阻止它们。
  • 问题是,如果我不将复制/赋值声明为私有,我会收到关于私有 unique_ptr 复制构造函数的错误。如果我不声明自己,移动构造函数编译器会尝试自动生成副本并失败
  • 如果 VS11 支持它,我不知道,但你总是可以告诉编译器使用 T(T&amp;&amp;) = default; 为你生成移动 c'tor。
  • 如果您= deleted 复制成员,您将生成移动成员。但是,VC++似乎根本没有实现move成员的生成。

标签: c++ visual-c++ c++11 visual-studio-2012 move-semantics


【解决方案1】:

不幸的是,C++11 的这一部分在不断变化。而且无论标准要说什么,VC11 都不可能实现它。所以就今天而言,我不相信你能指望生成的移动成员。

不过,这是一个很好的问题,我想得到一个很好的答案。

一般来说,如果您没有用户声明的复制成员或析构函数,编译器应该生成移动成员。 = default= delete 算作用户声明。如果您声明一个移动成员(例如移动构造函数),则不会隐式生成另一个。

不幸的是,C++11 继续说,有时移动成员在使用 =default 声明时会被隐式删除,有时它们的生成取决于基和成员是否具有移动成员或可简单复制。这太复杂了,有时会产生令人惊讶的行为。这是跟踪此错误的 CWG 问题:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1402

在我撰写本文时,该问题没有正确的建议解决方案。我预计这会在大约一周内改变。在俄勒冈州波特兰举行的 2012 年秋季 C++ 标准会议上,达成了一项协议,其内容基本上是:

  1. 编译器永远不会隐式删除移动成员。
  2. 移动成员​​的隐式生成将始终与= default 相同。
  3. 隐式生成将不取决于基地或成员的琐碎程度,也不取决于它们在移动时是否会抛出。

简而言之,我希望 CWG 1402 的更正措辞简单地说:

一般来说,如果你没有,编译器应该生成移动成员 用户声明的复制成员或析构函数。 = default= delete 算作用户声明。如果您声明一个移动成员(例如移动 构造函数),其他的不会隐式生成。 如果你 =default 是一个移动成员,你会得到一些移动的东西 每个基地和成员。

(适当的标准化)。我还没有看到会这样说的措辞。 Jason Merrill 正在为我们编写。

这意味着有时编译器会隐式生成投掷移动成员。但我们要的是简单的规则,但大多数时候都做正确的事(很少有惊喜)。

【讨论】:

  • 嗯,你可以依赖的基础概念,完全可预测,已经随着文本模式流消失了(产生 über-无法用标准 C++ 在 Windows 中编写 cat 的愚蠢情况(我们不要进入 echo))。所以我认为这个澄清正在进行中。移动语义,真的没那么重要。这是关于优化的复杂细节,可能会抛出移动构造函数,在引入额外故障模式的意义上已经不可靠——因此细节并不重要。
  • @Cheersandhth.-Alf 细节可能很重要,因为您依靠它来提高性能。幸运的是,据我所知,可以编写一个关于存在无抛出移动可用性的编译时断言
【解决方案2】:

为了更直接地回答这个问题,Visual Studio 不支持任何版本的隐式移动构造函数/赋值生成。因此,您必须始终手动将它们写出来。

【讨论】:

  • 我认为他们在 2012 年解决了这个问题。
  • @ChristianRau:不,但考虑到霍华德所说的,他们等待可能是件好事。
猜你喜欢
  • 2018-10-01
  • 2019-04-16
  • 1970-01-01
  • 1970-01-01
  • 2017-07-20
  • 2013-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多