【问题标题】:Disallow copy constructor but allow implicit copy from other type禁止复制构造函数,但允许来自其他类型的隐式复制
【发布时间】:2014-08-31 07:00:48
【问题描述】:

这是我的代码,我禁用了复制构造函数,但它也禁用了其他类型的隐式复制。在这种情况下有什么解决方法吗?

测试于:g++ (GCC) 4.7.1

struct item {
  int b;
};

class test {
 public:
  test(const test& copy) = delete;

  test(const item& a) {
    std::cout << "OK " << a.b << std::endl;
  }
};

int main() {
  test a = item{10}; //error: use of deleted function ‘test::test(const test&)’
}

【问题讨论】:

  • 如果可以的话,给test一个移动构造函数,如果不能的话,使用直接初始化语法。
  • 您使用的是哪个编译器和版本?
  • @IanCook:添加版本
  • 奇怪的是 gcc 和 clang 都给出了错误,但 MSVC2013 编译它很好。我不太了解标准,不知道哪个是正确的。
  • @Ian 我很确定这是一个 MSVC 扩展。

标签: c++ class c++11 copy-constructor


【解决方案1】:

要么给test一个移动构造函数:

test(test&&) = default;

或使用直接初始化:

test a{item{10}};

没有其他解决方法。目标类型为类类型(例如 test a = item{10};)的复制初始化始终需要可调用的复制或移动构造函数。


相关规则在§8.5 [dcl.init]/p17中规定:

如果目标类型是(可能是 cv 限定的)类类型:

  • 如果初始化是直接初始化,或者如果是复制初始化,其中源的 cv 不合格版本 type 与该类的类相同或派生类 目的地,构造函数被考虑。适用的构造函数 枚举(13.3.1.3),通过重载选择最好的 决议(13.3)。调用如此选择的构造函数进行初始化 对象,以初始化表达式或 expression-list 作为其 论点。如果没有构造函数适用,或者重载决议是 模棱两可,初始化格式不正确。
  • 否则(即,对于剩余的复制初始化情况),可以从源转换的用户定义转换序列 类型为目标类型或(使用转换函数时) 其派生类的枚举如 13.3.1.4 中所述, 最好的一个是通过重载决议(13.3)选择的。如果 转换无法完成或不明确,初始化是 格式不正确。使用初始化程序调用所选函数 表达式作为其参数;如果函数是构造函数,则调用 初始化 cv 不合格版本的临时版本 目的地类型。临时是prvalue。调用结果 (这是构造函数的临时情况)然后用于 直接初始化,根据上面的规则,对象是 复制初始化的目的地。在某些情况下,一个 允许实施以消除在此固有的复制 通过直接构造中间结果来直接初始化 进入正在初始化的对象;见 12.2、12.8。

源类型是item,目的类型是test,是复制初始化,所以属于第二个要点。使用test(const item&amp; a) 构造函数只有一个可用的转换,因此test 类型的prvalue 临时从item 构造,然后用于根据第一个要点直接初始化目标。这又必须调用test 的构造函数,该构造函数可以接受const test &amp;test &amp;&amp; 参数。即使省略了复制或移动,您仍然必须有这样的构造函数可用。

【讨论】:

  • 移动构造函数完成了这项工作!谢谢
【解决方案2】:

我能想到三个选项:

1) 移动构造函数
2) 赋值运算符+默认构造函数
3) 显式调用构造函数

#include <iostream>

struct item {
    int b;
};
struct test {
    test(const test& copy) = delete;
    test(const item& a) {
        std::cout << "OK " << a.b << std::endl;
    }
//  move:
    test(test&& from) {}
//  added:
    test() {}
    test& operator = (const test& src) = default;
};

int main() {
//fine after move constructor:
    test a = item{10};
//all fine with original
    test b(item{20});
//fine after adding .ctor() and op=
    test c; c = item{30};
}

【讨论】:

    猜你喜欢
    • 2010-12-21
    • 2012-05-15
    • 2015-07-13
    • 2018-08-16
    • 1970-01-01
    • 2014-11-18
    • 2011-09-12
    • 2018-10-17
    • 2019-05-14
    相关资源
    最近更新 更多