简体   繁体   English

要使用shared_ptr,这样安全吗?

[英]To use shared_ptr, is it safe ?

I have got some confused about shared_ptr. 我对shared_ptr感到困惑。

Say, I have classes: 说,我有课:

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;
}

Because b.get() != fb2, so it should crash when the program exit? 因为b.get()!= fb2,所以它应该在程序退出时崩溃? Or it is safe ? 还是安全的?

A shared_ptr<base> can safely take ownership of a derived* , even if base does not have a virtual destructor. 即使base没有虚拟析构函数, shared_ptr<base>也可以安全地获取derived*所有权。

However, this only works if shared_ptr knows what the most derived type of the object is when it takes ownership of it. 但是,这只有在shared_ptr知道对象获得所有权时最知道的对象类型时才有效。 If you were to remove the casts 如果你要删除演员表

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

then you'd definitely be okay. 那你肯定没问题。 With the casts, the shared_ptr cannot know what the most-derived type of the object is when it takes ownership of it, so the behavior is undefined, just as if you had said: 对于强制类型转换, shared_ptr在获取对象的所有权时无法知道对象的最派生类型,因此行为未定义,就像您说过:

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

The best thing to do is to follow the rule that "a base class destructor should be either public and virtual, or protected and nonvirtual." 最好的办法是遵循“基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的”这一规则

No, it's not safe. 不,这不安全。 foo and bar need virtual destructors, otherwise it's undefined what happens when the destructor of shared_ptr deletes the pointer it's holding. foobar需要虚拟析构函数,否则未定义当shared_ptr的析构函数删除它所持有的指针时会发生什么。 Of course, saying that it's not safe isn't the same as saying it should crash. 当然,说它不安全与说它应该崩溃是不一样的。

Alternatively, there's some magic[*] built into shared_ptr which means that if you don't cast to foo* , your code becomes safe: 或者,在shared_ptr中内置了一些魔法[*],这意味着如果你没有强制转换为foo* ,你的代码就会变得安全:

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

Either with the virtual destructor, or if you take out the casts, when shared_ptr comes to delete the pointer, the compiler will "know" how to adjust the pointer back to its original type, in order to call the correct destructors and free the memory. 无论是使用虚拟析构函数,还是取出了强制转换,当shared_ptr删除指针时,编译器将“知道”如何将指针调整回原始类型,以便调用正确的析构函数并释放内存。

The magic only works because fb1 is type foobar* , though. 这种魔法只能起作用,因为fb1foobar*类型。 Without the virtual destructor, the following is still unsafe: 没有虚拟析构函数,以下内容仍然不安全:

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

If you use shared_ptr like this, then there's no risk of doing that: 如果你像这样使用shared_ptr ,那么就没有这样做的风险:

fooptr f(new foobar());

You can also avoid the problem that in your code, that if the second call to new foobar() throws an exception, the first object is leaked. 您还可以避免代码中的问题,即如果第二次调用new foobar()抛出异常,则第一个对象会泄露。 If you're going to use shared_ptr to manage memory for you, then you need to get the memory under management as quickly as possible: 如果您打算使用shared_ptr为您管理内存,那么您需要尽快管理内存:

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

Now if the second line throws, f will be properly destructed and will delete the object. 现在,如果第二行抛出, f将被正确销毁并将删除该对象。

[*] "magic" = a constructor template, which stores in the shared_ptr a pointer to a function which will cast the stored pointer back to the correct type, and then delete it. [*]“magic”=一个构造函数模板,它在shared_ptr中存储一个指向函数的指针,该函数将存储的指针强制转换回正确的类型,然后将其删除。

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

It is not safe since you are using a C-Style cast in a C++ code. 由于您在C ++代码中使用C样式转换,因此不安全。

Do NOT use C-Style cast, use casts such as static_cast , dynamic_cast , const_cast or reinterpret_cast . 不要使用C-Style强制转换,使用诸如static_castdynamic_castconst_castreinterpret_cast强制const_cast Plus, no crash does not mean safety. 此外,没有崩溃并不意味着安全。

In fact, just remove the casts in this case. 实际上,在这种情况下只需删除演员表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM