C++ 智能指针、正向声明和C4150

C++ 智能指针、正向声明和C4150,c++,smart-pointers,forward-declaration,C++,Smart Pointers,Forward Declaration,因此,作为一个大型业余学习项目的一部分,我已经实现了一个基本完整的智能指针实现。它几乎做到了我要求它做的每一件事,除了一个小细节,如果我不能解决它,它可能会成为交易的破坏者。人为的例子: //Header1.h #include <Header2.h> class A { //Methods and such that involve class B in return type / arguments }; //Header2.h class A; //Forward de

因此,作为一个大型业余学习项目的一部分,我已经实现了一个基本完整的智能指针实现。它几乎做到了我要求它做的每一件事,除了一个小细节,如果我不能解决它,它可能会成为交易的破坏者。人为的例子:

//Header1.h

#include <Header2.h>

class A
{
//Methods and such that involve class B in return type / arguments
};

//Header2.h

class A; //Forward declaration of A, needed because A includes Header2.h

class B
{
public:
    SmartPointer<A> Ptr;
};
//Header1.h
#包括
甲级
{
//在返回类型/参数中涉及类B的方法等
};
//校长2.h
甲级//A的远期申报,需要,因为A包括表头2.h
B类
{
公众:
智能指针Ptr;
};
正如您所猜测的,前面的代码给了我
警告C4150:删除指向不完整类型“type”的指针;没有调用析构函数
。我知道为什么会这样;在
Header2.h
中,智能指针代码包括对
a
的正向声明实例的删除。如果我能包括
Header1.h
,没问题。我真的不想在这一点上重构

我听说boost智能指针以某种方式解决了这个问题。引入boost并不是本项目的目的,因为它实际上是一个爱好/学习项目。那么boost如何处理这个问题呢?在本例中,如何使智能指针的行为像原始指针一样?我有一些想法,但我想把问题浮起来,这样可以将想法列表筛选成有用的子集

转发声明,感谢您帮助我解决此问题

那么boost如何处理这个问题呢


Boost通过在智能指针类模板中使用
checked\u delete
而不是
delete
来处理此问题,因此需要完整定义
A

Boost维护指向可用于删除对象的函数的指针。它将其与实际指针一起存储在指针对象中。如果您想执行除调用delete之外的其他操作,可以传递自己的析构函数


shared_ptr构造函数是一个模板,它获取指向删除对象的模板函数的指针。因为它是在模板的构造函数中完成的,所以类只需要在构造对象时完成。所有其他操作都可以在没有完全访问权限的情况下执行

这可以通过在类B的CPP文件中定义析构函数(甚至是空的析构函数)来解决,如下所示:

//Header1.h
class A
{
//Methods and such that involve class B in return type / arguments
};


//Header2.h

class A; //Forward declaration of A

class B
{
public:
    ~B();

    SmartPointer<A> Ptr;
};


//Header2.cpp
#include "Header2.h"
#include "Header1.h" // obtain full definiton of A

B::~B() = default; // destructor here knows full definition of A
//Header1.h
甲级
{
//在返回类型/参数中涉及类B的方法等
};
//校长2.h
甲级//提前申报
B类
{
公众:
~B();
智能指针Ptr;
};
//校长2.cpp
#包括“Header2.h”
#包括“Header1.h”//获得对
B::~B()=默认值;//这里的析构函数知道A的完整定义
之所以这样做,是因为SmartPointer的析构函数是从编译器在B的析构函数中生成的代码中调用的,但定义~B的位置取决于您。如果您根本不指定它,它将在Header2.h中生成,其中缺少该定义,因此会出现警告。如果您在Header2.cpp中指定它,并将通常的声明放在Header2.h中,它显然会在Header2.cpp中正常工作,因为那里知道完整的定义。其他翻译单元(如Header1.cpp)也将正常工作,因为它们将看到~B的声明,而不会试图当场生成一个。相反,他们只需通过符号调用~B,这将由链接器稍后解析


在某些情况下,您可能还需要移动到cpp B的赋值运算符和/或,出于某种莫名其妙的原因,甚至是构造函数。

相关:@James:没错。没有其他“解决方案”,请参阅我链接的问题作为对您问题的评论。