12

我有这样的课:

class Inner;

class Cont
{
public:
    Cont();
    virtual ~Cont();
private:
    Inner* m_inner;
};

在 .cpp 中,构造函数创建一个Innerwith实例,new析构函数创建delete它。这工作得很好。
现在我想更改此代码以使用auto_ptr,所以我写:

class Inner;

class Cont
{
public:
    Cont();
    virtual ~Cont();
private:
    std::auto_ptr<Inner> m_inner;
};

现在,构造函数初始化了auto_ptr,析构函数什么也不做。

但它不起作用。当我实例化这个类时,问题似乎出现了。我收到这个警告:

警告 C4150:删除指向不完整类型“内部”的指针;没有调用析构函数

好吧,这显然很糟糕,我理解它为什么会发生,编译器不知道Inner实例化模板时的 d'torauto_ptr<Inner>

所以我的问题是:有没有办法auto_ptr像我在只使用普通指针的版本中那样使用前向声明?
必须对#include我声明的每个类都声明一个指针是一个巨大的麻烦,有时甚至是不可能的。这个问题一般是怎么处理的?

4

7 回答 7

13

您需要将定义的标头包含class Inner到实现所在的文件中Cont::~Cont()。这样你在头定义中仍然有一个前向声明,class Cont编译器看到class Inner定义并可以调用析构函数。

//Cont.h
class Inner; // is defined in Inner.h
class Cont 
{ 
    virtual ~Cont(); 
    std::auto_ptr<Inner> m_inner;
};

// Cont.cpp
#include <Cont.h>
#include <Inner.h>

Cont::~Cont()
{
}
于 2009-12-23T10:28:01.050 回答
4

原来只有当我使 c'tor 内联时才会出现问题。如果我将 c'tor 放在 cpp 中,那么在Inner一切正常之后。

于 2011-06-06T13:10:20.800 回答
3

你可以考虑 boost::shared_ptr() 代替。它没有实际的缺点而不是性能,并且对前向声明更加友好:

boost::shared_ptr<class NeverHeardNameBefore> ptr;

没关系,上面没有额外的声明。

shared_ptr 比 auto_ptr 做的更多,例如引用计数,但如果您不需要它,它应该不会造成伤害。

于 2009-12-23T10:32:12.450 回答
3

这似乎很荒谬,但我通过添加#include <memory>到 Cont.h 文件解决了同样的问题。

于 2012-12-05T12:45:28.830 回答
2

正如其他人指出的那样,如果您在 cont.cpp 文件中实现析构函数并包含 inner.h,则标头中的前向声明是可以的。

问题可能在于使用 Cont。在每个使用(并销毁)Cont 的 cpp 中,您必须包含 cont.h 和 inner.h。这解决了我的问题。

于 2011-06-15T08:30:00.743 回答
0

这个问题(deleting object with private destructor)和这个问题(how to write iscomplete template)可能会对你有所帮助。

于 2009-12-23T10:46:54.373 回答
0

从技术上讲,您不应该实例化具有不完整类型的标准库模板,尽管我知道没有任何实现方式不起作用。在实践中,Sharptooth 的回答也是我推荐的。

对 impl 指针使用裸指针确实没有任何问题,只要您在析构函数中对其调用 delete 即可。您可能还应该实现或禁用复制构造函数和赋值运算符。

于 2009-12-24T01:45:46.850 回答