【问题标题】:Force compiler to emit error on move constructor not defined with a base class deleted copy ctor强制编译器在未使用基类删除的复制 ctor 定义的移动构造函数上发出错误
【发布时间】:2018-12-12 16:18:27
【问题描述】:

考虑一个防止复制构造和复制分配的基类,如下所示:

class NonCopyable {
    public:
        NonCopyable() = default;
        ~NonCopyable() = default;

        NonCopyable(NonCopyable const&)                 = delete;
        NonCopyable& operator=(NonCopyable const&)      = delete;
};

我们的开发人员现在可以包含此类,并使用它来禁用继承类的复制,如下所示:

class CopyTest : public NonCopyable {
    public:
        CopyTest() {
            std::cout << "copy test created" << std::endl;
        }

        ~CopyTest() {
            std::cout << "copy test deleted" << std::endl;
        }
};

当我尝试使用 CopyTest 类时:

CopyTest ct, ct1(ct);

CopyTest ct;
CopyTest ct1 = ct2;

编译器发出错误:use of deleted function xxx(其中 xxx 是我删除的复制 ctor 或复制运算符)

那么,如果我想std::move 一个CopyTest 对象:

CopyTest ct;
CopyTest ct1 = std::move(ct);

编译器发出相同的错误(使用已删除的函数 xxx - 其中 xxx 仍然是我的复制 ctor 或赋值运算符)。

如果我提醒正确,那是因为开发者没有定义正确的移动ctor/赋值运算符。

是否可以强制编译器告诉 CopyTest 类的开发者移动错误在这里,因为他没有定义正确的移动 ctor/assignement 运算符,而不是因为复制 ctor/assignement运算符在基类上被删除了吗?

平台:

Debian 9

GCC 6.3.0

编译标志:

-fpermissive -ggdb -std=c++11

【问题讨论】:

  • 任何优秀的开发人员都知道这个错误的可能原因是缺少移动构造函数(毕竟他使用std::move)。我不会担心的。
  • 我同意你的观点,但我不想依赖其他人也不想依赖我可能的技能,并认为像我这样的初学者更容易理解确切的编译器错误......跨度>
  • 编译器错误是exact:隐式定义的move构造函数被删除,因为copy ctor是。

标签: c++ c++11 inheritance deleted-functions


【解决方案1】:

添加

    NonCopyable(NonCopyable &&)                 = delete;
    NonCopyable& operator=(NonCopyable &&)      = delete;

现在抱怨基类 move ctor 被删除。

【讨论】:

  • 这里的目标是知道编译器是否可以抱怨子类 move ctor 不存在,而不是基类 move ctor 已删除?
  • @Ayak973 子类获得为其编写的移动 ctor,但失败因为基类有一个已删除的移动 ctor。编译器在说为什么不能为你编写派生类的移动 ctor。
  • 我的推理是有偏见的,我现在更好地理解你的评论
【解决方案2】:

正式地说,隐式生成的移动 ctor/assignment 在基类NonCopyable 本身中定义为“已删除”。 “已删除”的移动 ctor/assignment 只是被重载决议忽略(而不是在严格意义上被删除)。由于NonCopyable 不可复制且不可移动,因此任何子类都将其隐式(并且=默认)复制和移动操作定义为已删除。

在严格的 iso c++ 下,您的设计具有想要的语义,但不幸的是,大多数编译器并不严格执行所谓的 五规则,而只执行 隐式删除 规则。例如,让用户为类声明析构函数意味着所有复制和移动操作的隐式(和=默认)定义将被删除,但我不知道编译器在隐式编译时无法编译或发出警告声明的复制构造函数将是用于此类的 ODR。

我遇到了这个错误报告 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58407#c16 。这表明编译器可能会开始强制执行或警告违反五项规则

【讨论】:

  • “五法则”不是语言的规则。
  • @Deduplicator 我知道,这更像是一个指导方针,但我用它作为捷径。
猜你喜欢
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多