复制构造函数的“尝试引用已删除的函数”

"attempting to reference a deleted function" for copy constructor

提问人:Dan 提问时间:8/23/2019 最后编辑:Dan 更新时间:8/28/2019 访问量:702

问:

我试图绕过 5 法则。

我有一个类,它定义了一个自定义析构函数,所以它似乎是 5 规则的一个很好的候选者。这个类在其构造函数中创建了一些资源,所以我的第一个想法是我应该防止复制:Renderable

class Renderable {

public:

    Renderable(const Sprite&) {
        // Allocate resources
    }

    ~Renderable() {
        // Free resources
    }

    // Prevent copying
    Renderable(const Renderable& other) = delete;

}

我还有另一个类,它在其构造函数的初始值设定项列表中创建一个:UnitRenderable

class Unit {

public:

    Unit(const Sprite& sprite) :
            renderable(Renderable(sprite)) {}

private:

    Renderable renderable;

}

我希望这会调用常规构造函数,但相反,我收到错误:Renderable

Renderable::Renderable(const Renderable &)':尝试引用已删除的函数

为什么这试图调用复制构造函数?

我什至尝试将调试行添加到复制构造函数中,但没有打印任何内容:

Renderable(const Renderable& other) : sprite(other.sprite) {
    std::cout << "copy constructor";
}
C++ 复制构造函数 三法则

评论

0赞 NathanOliver 8/23/2019
我们能得到一个最小的可重复的例子吗?
2赞 Chris Dodd 8/23/2019
因为你显式调用了复制构造函数,可以省略它,但前提是它没有被删除......
1赞 NathanOliver 8/23/2019
即使删除了移动和复制运算符,@ChrisDodd保证的复制省略仍然有效: coliru.stacked-crooked.com/a/3b362cf2fe731f71
1赞 Ted Lyngmo 8/23/2019
行不通?Unit::Unit(const Sprite& sprite) : renderable(sprite) {}
0赞 Chris Dodd 8/23/2019
@NathanOliver:在该示例中,您将获得一个默认的移动 CTOR,因为没有用户定义的析构函数(与 OP 的代码相比)

答:

4赞 David Schwartz 8/23/2019 #1

首先,创建一个 .然后你试着用它来构造。从概念上讲,除了复制构造函数之外,还能使用什么?Renderable(sprite)RenderablerenderableRenderable

为什么要创建一个初始化?该步骤不是必需的,并且不起作用,因为您没有复制构造函数。您已经明确表示,您不希望在概念上使用复制构造函数的代码工作。Renderablerenderable

评论

1赞 NathanOliver 8/23/2019
除了复制构造函数之外,还能使用什么?C++17 的保证复制省略说直接构造函数: coliru.stacked-crooked.com/a/b8874fa5edf90564
0赞 David Schwartz 8/23/2019
我想我应该澄清一下,我的意思是概念上的,而不是实际执行的。
1赞 NathanOliver 8/23/2019
甚至在概念上。你有一个 prvalue,它实际上并没有创建一个临时值。
1赞 M.M 8/23/2019
@NathanOliver他们可能使用的是 C++17 之前的编译器
1赞 David Schwartz 8/23/2019
@Dan 要提供给 构造函数的值是 。由于这是一个初始化列表,因此您正在构造要初始化的对象是给定的。renderablesprite
1赞 Sam Varshavchik 8/23/2019 #2

为什么这试图调用复制构造函数?

因为

  renderable(Renderable(sprite)) {}

这将构造一个临时对象,然后使用它来构造类成员。那将是一个Renderablerenderable

我什至尝试在复制构造函数中添加调试行,但什么都没有 印刷:

这是因为这是允许编译器执行复制省略的情况之一。即使编译器优化了临时+复制构造,构造函数也必须仍然存在。有关该类的某些内容会导致删除默认的复制构造函数。这可能有几个原因,但你没有提供有关你的班级的足够信息来确定可能的原因是什么。

评论

0赞 Ted Lyngmo 8/23/2019
它被显式删除:Renderable(const Renderable& other) = delete;
0赞 NathanOliver 8/23/2019
@TedLyngmo在C++17中无关紧要:coliru.stacked-crooked.com/a/3b362cf2fe731f71
0赞 Ted Lyngmo 8/23/2019
@NathanOliver 这是对“关于类的某些东西导致默认复制构造函数被删除”的评论,但也许我误解了。
0赞 Dan 8/23/2019
@TedLyngmo 当我添加调试行时,复制构造函数没有被删除。
0赞 Ted Lyngmo 8/23/2019
@Dan 否,但您也没有收到有关已删除的复制构造函数的错误。编译器发现它实际上可以省略所有复制(这就是您没有看到消息的原因)。"copy constructor"
3赞 Paul Sanders 8/23/2019 #3

除了别人说的,我想你的意思是写:

Unit::Unit(const Sprite& sprite) :
    renderable(sprite) {}

这将调用转换构造函数直接初始化,不涉及复制。Renderable(const Sprite&)renderable

现场演示

评论

0赞 Dan 8/23/2019
这是完全正确的,谢谢。我不知道这会隐式调用构造函数。Renderable