要使用shared_ptr,这样安全吗?

时间:2010-11-16 15:21:48

标签: c++ shared-ptr

我对shared_ptr感到困惑。

说,我有课程:

class foo {
     int _f;
};
typedef std::shared_ptr<foo> fooptr;

class bar {
    int _b;
};
typedef std::shared_ptr<bar> barptr;

class foobar : public foo, public bar {
    int _fb;
};

int main () {

    foobar *fb1 = new foobar();
    foobar *fb2 = new foobar();

    fooptr f((foo *)fb1);
    barptr b((bar *)fb2);

    return 0;
}

因为b.get()!= fb2,所以当程序退出时它会崩溃吗?还是安全的?

4 个答案:

答案 0 :(得分:10)

即使shared_ptr<base>没有虚拟析构函数,derived*也可以安全地获得base的所有权。

但是,这仅在shared_ptr知道对象的所有权最多时才知道该对象的所有权。如果您要删除演员表

fooptr f(fb1);
fooptr b(fb2);
那时你肯定没问题。使用强制类型转换时,shared_ptr无法知道对象的最大派生类型是什么,因此行为是未定义的,就像您曾说过:

foo* f = new foobar();
delete f;

最好的办法是遵循"a base class destructor should be either public and virtual, or protected and nonvirtual."

的规则

答案 1 :(得分:7)

不,这不安全。 foobar需要虚拟析构函数,否则未定义当shared_ptr的析构函数删除它所持有的指针时会发生什么。当然,说它不安全与说它应该崩溃是不一样的。

或者,shared_ptr中内置了一些魔法[*],这意味着如果你不转换为foo*,你的代码就会变得安全:

fooptr f(fb1);
barptr b(fb2);

使用虚拟析构函数,或者如果取出强制转换,当shared_ptr删除指针时,编译器将“知道”如何将指针调整回其原始类型,以便调用正确的析构函数和释放记忆。

只有fb1foobar*类型才能使用魔法。如果没有虚拟析构函数,以下内容仍然不安全:

foo *fb = new foobar();
fooptr f(fb);

如果你像这样使用shared_ptr,那么就没有这样做的风险了:

fooptr f(new foobar());

您还可以避免代码中的问题,即如果第二次调用new foobar()引发异常,则会泄漏第一个对象。如果您打算使用shared_ptr为您管理内存,那么您需要尽快管理内存:

fooptr f(new foobar());
barptr b(new foobar());

现在,如果第二行抛出,f将被正确销毁,并将删除该对象。

[*]“magic”=一个构造函数模板,它在shared_ptr中存储一个指向函数的指针,该函数将存储的指针强制转换回正确的类型,然后将其删除。

答案 2 :(得分:0)

foobar不是多态类,因此这段代码很可能会导致无效的指针释放。

答案 3 :(得分:-1)

由于您在C ++代码中使用C样式转换,因此不安全。

请勿使用C风格演员表,使用static_castdynamic_castconst_castreinterpret_cast等演员表。 此外,没有崩溃并不意味着安全。

事实上,在这种情况下只需删除演员表。