【问题标题】:Unreasonably deleted move constructor不合理地删除移动构造函数
【发布时间】:2017-03-04 12:32:17
【问题描述】:

我有一个带有明确删除的复制构造函数的类,比如说NonCopyable。然后有一个类Base1,其成员类型为NonCopyable。另一个类Base2Base1 为父类。最后 - 一个 Derivative 类,其父级是 Base2

由于NonCopyable 是不可复制的,很明显Base1Base2Derivative 也是不可复制的。但似乎也删除了移动构造函数(和赋值运算符)。

在这里测试一下:

以下行给出了这些错误:
Derived d1, d2 = std::move(d1);

GCC: 'Derived::Derived(Derived&&)' 被隐式删除,因为默认定义格式不正确: 派生类:
其余错误只是声称 Base1Base2 复制 ctor 被隐式​​删除,这并不奇怪

MSVC: 错误 C2280: 'Derived::Derived(const Derived &)': 试图引用已删除的函数

在提供的链接中,也有注释行给出了类似的错误。请取消注释它们以查看我想向您展示的更多错误(例如,remove_if 未注释它抱怨删除的移动 (在 GCC 上) /copy (在 MSVC 上)分配运算符)。
我想要实现的是使 Derivative(及其基础也是)可移动,但不可复制。

我正在使用 Visual Studio 2015 并得到与我提供的 msvc 链接中完全相同的错误,但我不确定在 rextester.com 上使用哪个版本的 MSVC 进行编译.

应@Richard Critten 的要求,我也在此处粘贴代码:

    class NonCopyable
    {
    public:
       NonCopyable() { }
       NonCopyable(const NonCopyable &) = delete;
       NonCopyable & operator=(const NonCopyable &) = delete;
       NonCopyable(NonCopyable &&) { }
       NonCopyable & operator=(NonCopyable &&) { return *this; }
    };

     class Base1
     {
     public:
          virtual ~Base1() = default;

     private:
          NonCopyable m;
     };

     class Base2 :
        public Base1
     {
     public:
          virtual ~Base2() = default;
     };

     class Derived :
        public Base2
     {
     };



int main()
{
    std::vector<Derived> v;
    //std::remove_if(v.begin(), v.end(), [](const Derived &) { return true; });
    //v.emplace_back();
    Derived d1, d2 = std::move(d1);
}

【问题讨论】:

  • 你能在这里显示代码吗?我对随机链接过敏。此外,如果这个问题被证明是有用的,那么这里的代码更适合搜索,我们不必担心它会从链接的站点中删除。
  • @Someprogrammerdude 我认为Derived 不符合这些标准中的任何一个。但如果你看到我的错误,请告诉我它在哪里。
  • @Criss:一些实验表明BaseBase2 都必须声明它们的移动构造函数,但Derived 可以使用默认值。我不知道具体原因。
  • 问题可以是seen with Base1 already;其余的都是不必要的并发症。未生成 Base1 的移动构造函数,因为它具有用户声明的析构函数。

标签: c++ c++11 inheritance move-semantics


【解决方案1】:

[class.copy]/9如果类X的定义没有明确声明移动构造函数,当且仅当

(9.4) — X 没有用户声明的析构函数。

Base1 有一个用户声明的析构函数,所以没有移动构造函数。由于不可复制成员,复制构造函数被隐式声明为已删除。所以Base1既不能复制也不能移动,当然Base2Derived也可以一起使用。

【讨论】:

  • 嗯。有用!但是...无论如何,我必须有Base1Base2 析构函数是虚拟的。所以......唯一的选择是明确定义移动构造函数?另外 - 你能提供一个链接到你从哪里得到报价吗?
  • 您可以将它们显式定义为默认值。然后,您还需要显式定义默认构造函数。引用来自 C++14 标准草案:isocpp.org/std/the-standard
  • 现在我终于想起来了。这是斯科特迈耶斯所做的。他注意到从具有类不变的类(由用户定义的析构函数表示)的默认移动的问题,并将其发布在 comp.std.c++ 和 comp.lang.c++ 中。进行了一些讨论,并对拟议的规则进行了修改。
猜你喜欢
  • 1970-01-01
  • 2018-03-26
  • 1970-01-01
  • 2018-02-10
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多