我有一个这样的课程:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
Inner* m_inner;
};
在.cpp中,构造函数使用Inner
和析构函数new
创建delete
的实例。这很好用。
现在我想更改此代码以使用auto_ptr
,所以我写道:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
std::auto_ptr<Inner> m_inner;
};
现在,构造函数初始化了auto_ptr
,而析构函数什么也没做。
但它不起作用。当我实例化这个类时,问题似乎就出现了。我收到了这个警告:
警告C4150:删除指针 不完全类型'内';没有 析构函数叫
嗯,这显然非常糟糕,我明白为什么会发生这种情况,编译器在实例化Inner
模板时不知道auto_ptr<Inner>
的信息
所以我的问题:有没有办法像我在只使用普通指针的版本中那样使用auto_ptr
和前向声明?
我必须#include
每个课程都会声明一个指针,这是一个很大的麻烦,有时甚至是不可能的。这个问题通常是如何处理的?
答案 0 :(得分: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()
{
}
答案 1 :(得分:4)
事实证明只有当我将内置c'tor时才会出现问题。如果我把c'tor放在cpp中,在Inner
取消后,一切都没问题。
答案 2 :(得分:3)
您可以考虑使用boost :: shared_ptr()。它没有实际的缺点而不是性能,并且对转发声明更加友好:
boost::shared_ptr<class NeverHeardNameBefore> ptr;
没关系,上面没有额外的声明。
shared_ptr不仅仅是auto_ptr,比如引用计数,但如果你不需要它,它不应该受到伤害。
答案 3 :(得分:3)
这似乎很荒谬,但我通过在Cont.h文件中添加#include <memory>
解决了同样的问题。
答案 4 :(得分:2)
如果在cont.cpp文件中实现析构函数并且包含inner.h,那么标题中的forward声明是可以的,正如其他人指出的那样。
问题可能在于使用Cont。在每个使用(和销毁)Cont的cpp中,你必须包含cont.h和inner.h。这解决了我的问题。
答案 5 :(得分:0)
This question(使用私有析构函数删除对象)和this question(如何编写iscomplete模板)可能会对您有所帮助。
答案 6 :(得分:0)
从技术上讲,您不应该使用不完整的类型来实例化标准库模板,尽管我知道没有实现它不起作用的实现。在实践中,Sharptooth的答案也是我推荐的。
对于impl指针使用裸指针确实没有任何问题,只要在析构函数中调用delete即可。您可能还应该实现或禁用复制构造函数和赋值运算符。