【问题标题】:C++ auto with member initializer syntax and deleted copy constructor具有成员初始化器语法和已删除复制构造函数的 C++ auto
【发布时间】:2016-04-19 04:33:39
【问题描述】:
class A
{
    int a;

public:

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

    A() : a {0}
    { }
};

int main()
{
    auto a = A {};
}

以上代码无法编译,我收到以下错误:C2280 'A::A(const A &)': 试图引用已删除的函数

我正在使用 Visual Studio 2015 编译器。我的理解是成员初始化语法编译器应该直接使用默认构造函数,这是在没有自动时会发生的情况,而我主要使用A a{}。所以我想知道在这种情况下与 auto 有什么关系。

【问题讨论】:

  • 您仍然可以使用auto&&
  • 如果没有auto,这也不起作用,那么您的问题是什么?
  • 即使复制构造函数被省略,它也必须是可访问的。

标签: c++


【解决方案1】:
auto a = A {};

仅当A 是可复制构造或可移动构造时才有效。您使用auto 的事实无关紧要。

A a = A {};

也是。

声明一个复制构造函数——即使是一个deleted——禁止隐式声明一个移动构造函数,所以你的类型A既不能复制构造也不能移动构造。如果添加行

A(A&&) = default;

A的主体,代码应该再次编译。

实际上,在这种情况下,编译器实际上不会调用任何复制或移动构造函数,而是直接在a 中构造对象。但是语言规则要求它仍然必须拒绝有意义的代码,因为是否允许一段代码不应该取决于可选的编译器优化。

这种行为在 C++17 中(很可能)change

【讨论】:

  • 这太好了,我一直想知道为什么,例如使用auto a = A{};时,class A{std::mutex m;}; 在 C++14 和 C++17 上的表现不同@
【解决方案2】:

您的理解是正确的,所以让我们一步一步来看看这里发生了什么。

A {};

如你所说,成员初始化语法,在这里完全符合规定。

auto a = (expression of some kind)

然后你正在构建auto a。执行类型推断后,这变得等价于...

A a = (expression of some kind)

这看起来像一个复制构造函数。你删除的那个。

【讨论】:

    【解决方案3】:

    你应该这样使用 auto:

    auto a = new A();
    

    如果你不想使用 auto,这是 c++11 的方式:

    A a{};
    

    【讨论】:

    • 不应该这样使用auto。拥有原始指针是 C++11 代码中的一个危险信号。而且这里也不需要堆分配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    相关资源
    最近更新 更多