问题 Unique_ptr和前向声明


说我有两个班:

“foo.h中”

#pragma once    
class Foo
{
public:
    Foo()
    {

    };

    ~Foo()
    {

    };
};

“啊”

#pragma once
#include <memory>

class Foo;

class A
{
public:
    A(){};
    ~A(){};

    std::unique_ptr<Foo> foo;
};

A持有 unique_ptr 的 Foo。我不想包括 Foo 在“A.h”,所以我向前宣布它。通过向前宣布课程 Foo 在“A.h”中,我得到一个编译时错误:

error C2027: use of undefined type 'Foo'
error C2338: can't delete an incomplete type  

所以我跟着 这个 有关如何避免此错误的文章,并将A的析构函数移入其自己的.cpp文件中,其中我还包含Foo:

“A.cpp”

#include "A.h"

#include "Foo.h"

A::A()
{

}

A::~A()
{

}

在“A.cpp”中实现A的析构函数后,我能够编译程序,因为类Foo在“A.cpp”中已知。这似乎是合乎逻辑的,因为unique_ptr需要完整的类型来调用它的析构函数。但令我惊讶的是,在评论出A的构造函数(在“A.h”以及“A.cpp”中)之后,我得到了同样的错误。这怎么可能?为什么编译器抱怨在A没有构造函数时无法调用Foo的析构函数?

编辑: 我上传了4个文件,因此您可以测试该程序。 我正在使用Visual Studio 2013的MSVC ++。

http://www.filedropper.com/test_61


8105
2017-12-06 21:31


起源

A 当你注释掉你的构造函数时,它有一个构造函数:编译器提供了一个默认构造函数,这个构造函数得到一个内联定义。 - dyp
当您注释掉构造函数时,编译器将隐式定义它,作为内联函数(即在头文件中不在.cpp文件中)。看起来您的编译器认为隐式定义的默认构造函数可能想要销毁 unique_ptr,可能是在构造函数(或其他成员)的主体抛出异常并且需要再次销毁unique_ptr成员的情况下。您上面显示的代码不应该有这种效果,因为没有其他成员。 - Jonathan Wakely
在上面的代码中,默认构造函数不需要销毁它(所以如果编译器认为它需要那是一个编译器错误),但是如果你的真实代码在类之后定义的类中有其他成员 unique_ptr 成员,并且构造其中一个成员可能会失败,异常,unique_ptr成员将需要被销毁。你在炫耀吗? 精确 您正在测试的代码,或者实际上没有给出相同错误的简化版本? - Jonathan Wakely
哎呀,我错了,构造函数确实需要知道完整的类型,正是由于Chris Drew在下面给出的原因。因此构造函数需要与析构函数一起定义为非内联。 - Jonathan Wakely
所以当使用unique_ptr时,类总是需要构造函数和析构函数的完整类型吗?我很困惑,因为你在网上找到的所有文章都提到了析构函数中完整类型的需要(就像我在初始问题中提到的文章一样)。 - abcheudg234


答案:


构造函数需要以与析构函数相同的方式访问删除器:异常安全性要求构造函数能够在构造函数的主体抛出的情况下回滚所有成员的初始化:

[C++14: 12.6.2/10]: 在非委托构造函数中,可能会调用每个可能构造的类类型子对象的析构函数(12.4)。 [ 注意: 此规定确保在抛出异常时可以为完全构造的子对象调用析构函数(15.2)。 - 尾注]

有关:


14
2017-12-23 16:34





'A'不可能没有构造函数。

如果您对您编写的构造函数进行注释,编译器将为您创建一个默认构造函数,它不一定与您定义的构造函数位于同一位置。导致问题。


-1
2017-12-06 21:52



但为什么我必须在A.cpp中定义构造函数呢?我知道编译器抱怨A的析构函数必须在包含Foo.h的地方定义 - 这样它就是一个完整的类型而A的析构函数实际上可以破坏Foo。但我不明白为什么A的CONstructor也必须在A.cpp中定义。您可以通过复制类并在main()中实例化A来尝试代码。在注释掉A的构造函数时,代码将无法编译。 - abcheudg234
你在起诉什么编译器? - Alex_HG
我正在使用Visual Studio 2013的MSVC ++编译器。 - abcheudg234
我正在起诉Visual Studio 2013的MSVC ++编译器。我知道@ R.MartinhoFernandes也是如此。 - Lightness Races in Orbit