智能指针、前置声明和C4150

3

作为一个大型爱好学习项目的一部分,我已经实现了一个几乎完整的智能指针实现。它几乎可以满足我所有的需求,但有一个细节问题可能会成为致命缺陷,如果我不能解决它。举个例子:

//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;
};

前面的代码,正如你所猜测的那样,给我带来了warning C4150: deletion of pointer to incomplete type 'type'; no destructor called。我知道这是为什么;在Header2.h中,智能指针代码包括对A的一个前向声明实例的删除。如果我能够包含Header1.h,那就没有问题了。但我现在不想重构。

我听说boost智能指针已经解决了这个问题。但引入boost并不是这个项目的目的,因为它基本上是一个业余/学习项目。那么boost是如何解决这个问题的?在这种情况下,我该如何让智能指针的行为像原始指针一样?我有几个想法,但我觉得把这个问题放到SO上可以把想法列表减少到一个有用的子集。

提前感谢您帮助我解决这个问题。


相关:删除不完整类型的对象 - fredoverflow
3个回答

2
那么Boost是如何处理这个问题的呢?在智能指针类模板中使用checked_delete代替delete,从而需要完整定义A

2
@James:没错。没有其他的“解决方案”,请看我在你问题下面评论中提供的链接。 - fredoverflow

1
Boost维护一个指向可用于删除对象的函数的指针。它将其存储在指针对象中,同时也存储实际指针。如果您想要执行除调用delete之外的其他操作,则可以传递自己的析构函数。
shared_ptr构造函数是一个模板,它获取指向模板函数的指针来删除对象。由于它在模板中完成构造函数,因此只有在构造对象时才需要完整访问类。所有其他操作都可以在没有完全访问的情况下执行。

0
这个问题可以通过在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

这个方法之所以有效,是因为 SmartPointer 的析构函数被编译器在 B 的析构函数中生成的代码调用,但 ~B 的定义取决于你在哪里定义它。如果你根本没有指定它,它将在 Header2.h 中生成,而该定义缺失,因此会出现警告。如果你在 Header2.cpp 中指定它并在 Header2.h 中放置通常的声明,那么在 Header2.cpp 中它显然会正常工作,因为完整的定义已知。其他翻译单元(如 Header1.cpp)也会正常工作,因为它们将看到 ~B 的声明,并且不会尝试在现场生成一个。相反,它们只会通过符号调用 ~B,这将由链接器稍后解析。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接