2010-11-16 56 views
6

我对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,所以应该崩溃,当程序退出?或者它是安全的?

回答

10

A 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."

+0

+1,你打我解释模板的构造函数。 – 2010-11-16 15:32:41

+0

谢谢你的回复:) – ddh 2010-11-16 15:53:05

0

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

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中存储一个函数指针,该函数将存储的指针转换回正确的类型,然后将其删除。

+0

如果foo和bar都具有虚拟析构函数,那么它是安全的吗? – ddh 2010-11-16 15:29:04

+0

尽管如此,明确的转换仍然存在,而且它是安全的,因为'shared_ptr'有一个模板化的构造函数,它可以确保通过最初传递给构造函数的指针的类型进行销毁,而不是'shared_ptr'的模板参数,破坏。在基类中有一个虚拟析构函数仍然是非常可取的;但这在技术上并不危险。 – 2010-11-16 15:30:25

+0

我认为在shared_ptr的析构函数中,应该有“delete ptr”,并且delete的操作可以:1)调用对象的去零域,2)释放内存。但是,如果所有内存都是0x10000,但shared_ptr得到的是0x10004,那么应该有一些问题? – ddh 2010-11-16 15:30:53

-1

这是不安全的,因为您在C++代码中使用C风格转换。

不要使用C风格的演员阵容,用蒙上如static_castdynamic_castconst_castreinterpret_cast。另外,没有碰撞并不意味着安全。

事实上,在这种情况下只需移除铸件。

+0

'dynamic_cast'拼写'dynamic_cast',句点。 – curiousguy 2017-01-19 04:24:07