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

Initialization of const reference member with deleted copy constructor

本文关键字:初始化 const 引用 成员 构造函数 复制 删除      更新时间:2023-10-16

这段代码在B中有一个const A& a成员,其中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};
}

哪一个编译器是对的?

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;
    ^

Ideone:http://ideone.com/x1CVwx

您的示例可以简化为

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
}

ar2在gcc-4.8上初始化失败,出现错误

error: use of deleted function ‘A::A(const A&)’

它在clang3.4和gcc4.9上进行了干净的编译。这是《禁止化学武器公约》第1288号决议的结果。

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

§8.5.4/3[dcl.init.list]

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

当然,这意味着ar2的初始化需要一个可访问的复制构造函数,因此出现了错误。


N3797中的语言发生了变化,其中从包含单个元素的初始值设定项列表进行的初始化优先于上面引用的大小写。

--否则,如果初始化器列表具有类型为E的单个元素,并且T不是引用类型或者其引用类型是与E相关的引用,则从该元素初始化对象或引用;...
--否则,如果T是引用类型,则根据引用的初始化类型,T引用的类型的prvalue临时被复制列表初始化或直接列表初始化,并且引用被绑定到该临时。

因此,gcc 4.9和clang 3.4正在执行问题1288的解决方案,而gcc 4.8则遵循C++11标准中的措辞。