我对以下代码执行的操作有点困惑:
class Base
{
public:
Base() = default;
Base(const Base &) =delete;
Base &operator=(const Base &) = delete;
Base(const char*) {}
};
class Holder
{
public:
Holder() = default;
private:
// Base b = Base();
Base b2 = {};
};
int main()
{
Holder h;
}
在这个版本中,它会编译,但如果我取消评论Base b = Base();
,则会出现以下错误:
main.cpp:15:17: error: use of deleted function 'Base::Base(const Base&)'
Base b = Base();
^
main.cpp:5:6: note: declared here
Base(const Base &) =delete;
^
我无法在标准中找到为什么它会尝试为Base b = Base()
初始化程序调用复制构造函数,为什么它不会调用Base b2 = {}
...或者这只是某个段落隐藏在一个段落中的一些小晦涩难懂的东西吗?
您能否(短)解释为何会发生这种情况?
(coliru:http://coliru.stacked-crooked.com/a/c02ba0293eab2ce5)
答案 0 :(得分:8)
这是因为,从概念上讲,该行构造自Base()
,需要复制/移动构造函数。你没有意识到这一点的可能原因是因为该表达式通常会触发复制省略:标准优化。它是C ++陷阱之一。
(31.3) - 当一个临时的类对象没有绑定到一个 reference(12.2)将被复制/移动到具有相同的类对象 cv-unqualified类型,可以省略复制/移动操作 将临时对象直接构造到目标中 省略了复制/移动。
至于为什么Base b2 = {}
有效,请参阅
(3.4) - 否则,如果初始化列表没有元素而T是a 具有默认构造函数的类类型,对象是 值初始化。
你可以Base b;
。
答案 1 :(得分:5)
T object = {arg1, arg2, ...};
是list initialization的语法。没有涉及复制。
T object = T()
不是列表初始化。右手操作数构造一个值初始化的临时值,object
从中进行移动或复制初始化。移动和复制可以省略,但类型必须是可移动的或可复制的,否则不允许这样做。
答案 2 :(得分:0)
真正的原因是因为您忘记了关键字“ explicit”,您应该更改代码
Base(const Base &) =delete;
收件人:
explicit Base(const Base &) = delete;
让我解释一下原因,在“ Holder”类中,Base b = Base()将:
Base obj = value;
成为
Base obj(value);
因此,只需添加关键字“ explicit”将解决此问题。 ^ _ ^