为什么boost::scoped_ptr不能在继承场景中工作
Why does boost::scoped_ptr not work in inheritance scenario?
使用boost::scoped_ptr保存引用时,不会调用派生对象的析构函数。当使用boost::shared_ptr时,
#include "stdafx.h"
#include <iostream>
#include "boost/scoped_ptr.hpp"
#include "boost/shared_ptr.hpp"
using namespace std;
class Base
{
public:
Base() { cout << "Base constructor" << endl ; }
~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base
{
public:
Derived() : Base() { cout << "Derived constructor" << endl; }
~Derived() { cout << "Derived destructor" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
boost::scoped_ptr<Base> pb; // replacing by shared_ptr does call Derived destructor
pb.reset(new Derived());
cout << "Program ends here" << endl;
}
你能解释一下吗?是否有一个"黄金法则"不使用scoped_ptr多态成员变量?
它之所以适用于shared_ptr
,是因为它实现了一个特殊的构造函数和reset()
方法,如下所示:
template<class T>
class shared_ptr
{
public:
// ...
// Note use of template
template<class Y> explicit shared_ptr(Y * p);
// ....
// Note use of template
template<class Y> void reset(Y * p);
// ....
};
当调用这个构造函数或reset()
时,shared_ptr
"记住"原始类型Y
,因此当引用计数为零时,它将正确调用delete
。(当然p
必须转换为T
。)这在文档中有明确的说明:
为了便于记忆,这个构造函数被改成了模板传递的实际指针类型。析构函数将调用delete相同的指针,完整的原始类型,即使当T没有虚析构函数,或者是void. ...]
scoped_ptr
和reset()
的构造函数是这样的:
template<class T>
class scoped_ptr : noncopyable
{
public:
// ...
explicit scoped_ptr(T * p = 0);
// ...
void reset(T * p = 0);
};
所以scoped_ptr
没有办法"记住"原始类型是什么。当需要delete
指针时,它实际上是这样做的:
delete this->get();
和scoped_ptr<T>::get()
返回一个T*
。因此,如果scoped_ptr
指向的不是T
,而是T
的子类,则需要实现virtual
析构函数:
class Base
{
public:
Base() { cout << "Base constructor" << endl ; }
virtual ~Base() { cout << "Base destructor" << endl; }
};
那么为什么scoped_ptr
不像shared_ptr
那样为这种情况实现一个特殊的构造函数呢?因为"scoped_ptr模板是满足简单需求的简单解决方案"。shared_ptr
做了大量的记账来实现其广泛的功能。请注意,intrusive_ptr
也不"记住"指针的原始类型,因为它意味着尽可能轻量级(一个指针)。
与shared_ptr<>
不同,scoped_ptr<>
不会"记住"传递给其构造函数的确切类型。http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htmsynopsis告诉我们:
template<class T> class scoped_ptr : noncopyable {
public:
typedef T element_type;
explicit scoped_ptr(T * p = 0); // never throws
~scoped_ptr(); // never throws
void reset(T * p = 0); // never throws
T & operator*() const; // never throws
T * operator->() const; // never throws
T * get() const; // never throws
operator unspecified-bool-type() const; // never throws
void swap(scoped_ptr & b); // never throws
};
。它不知道你传递了什么,它只知道T
,在你的例子中是Base
。为了启用正确的删除,如果适合您的设计,您需要使用shared_ptr<Base>
,或者您必须让Base
具有虚拟析构函数
class Base
{
public:
Base() { cout << "Base constructor" << endl ; }
virtual ~Base() { cout << "Base destructor" << endl; }
};
作为经验法则(参见Meyers):
如果想通过基类进行多态删除,则将基类析构函数设为虚函数
与scoped_ptr<>
不同,shared_ptr<>
显式地记住传递给构造函数的指针类型:
...
template<class Y> shared_ptr(shared_ptr<Y> const & r);
...
而文档说
为了记住传递的实际指针类型,这个构造函数被改成了模板。即使在T没有虚析构函数或为void时,析构函数也将使用相同的指针调用delete,并完成其原始类型。
这可以通过混合运行时多态性和静态多态性来实现。
为了通过指向基类的指针调用派生类的析构函数,需要有一个虚析构函数
- 为什么C++需要公共继承,忽略朋友声明,才能使动态向下工作?
- 继承引用无法正常工作
- C++ 继承:基类中重载 operator+ 的 2 次在派生类中无法正常工作
- c++ 中的函数重载如何在没有钻石继承的情况下工作?
- 代码在虚拟函数和继承方面未按预期工作
- Omnet++ 如何从同一工作区中不同项目中的 cSimpleModule 继承
- 在这种情况下,继承类如何工作??.
- 继承实际上是如何工作的
- 朋友功能是否继承?为什么基类朋友功能在派生的类对象上工作
- C++ 继承无法正常工作
- 继承默认构造函数在 gcc 中失败并在 clang 中工作,哪个有错误?
- 使用模板无法按预期工作进行继承和强制转换
- 模板类实例化如何与类继承协同工作
- 如何使用模板或继承使以下代码工作
- 多重继承强制转换未按预期工作
- c++多重继承强制转换是如何工作的
- 将 Boost.Serialization 直接与虚拟钻石继承一起工作
- 使用虚拟基类时,多重继承是如何工作的
- 虚拟继承是如何工作的
- 继承人类不工作