使用已删除的复制构造函数初始化const引用成员

sma*_*ill 8 c++ reference uniform-initialization c++11

这个代码,其中有一个const A& a成员B,其中A有一个已删除的拷贝构造函数,不能在GCC 4.8.1中编译,但它在clang 3.4中工作正常:

class A {
public:
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
};

class B{
public:
    B(const A& a)
        : a{a}
    { }
private:
    const A& a;
};

int main()
{
    A a{};
    B b{a};
}
Run Code Online (Sandbox Code Playgroud)

哪一个编译器是对的?

GCC中的错误是:

prog.cpp: In constructor ‘B::B(const A&)’:
prog.cpp:11:14: error: use of deleted function ‘A::A(const A&)’
        : a{a}
            ^
prog.cpp:4:5: error: declared here
    A(const A&) = delete;
    ^
Run Code Online (Sandbox Code Playgroud)

Ideone:http://ideone.com/x1CVwx

Pra*_*ian 9

你的例子可以简化为

class A {
public:
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
};

int main()
{
  A a{};
  A const& ar1(a); 
  A const& ar2{a}; // fails on gcc 4.8
}
Run Code Online (Sandbox Code Playgroud)

ar2gcc-4.8上的初始化失败并带有错误

error: use of deleted function ‘A::A(const A&)’
Run Code Online (Sandbox Code Playgroud)

它在clang3.4和gcc4.9上完全编译.这是CWG 第1288号决议的解决结果.

N3337包含以下用于列表初始化的语言:

§8.5.4/ 3 [dcl.init.list]

类型的对象或引用的列表初始化T定义如下:
- ...
- 否则,如果T是引用类型,则引用的类型的prvalue临时值 T是列表初始化的,并且引用绑定到该临时类型

当然,这意味着初始化ar2需要一个可访问的拷贝构造函数,因此也就是错误.


N3797中的语言已更改,其中包含单个元素的初始化列表的初始化优先于上面引用的情况.

- 否则,如果初始化列表具有单个元素类型E且且T不是引用类型或其引用类型与引用相关E,则从该元素初始化对象或引用; ...
- 否则,如果T是引用类型,则引用类型的prvalue临时值T是copy-list-initialized或direct-list-initialized,具体取决于引用的初始化类型,引用绑定到该临时值.

所以gcc 4.9和clang 3.4正在实现问题1288的解决方案,而gcc 4.8遵循C++ 11标准中的措辞.

  • @MattMcNabb复制构造函数中的副作用是真正的错误:P (2认同)