开发者

To use shared_ptr, is it safe ?

I have got some confused about 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? Or it is safe ?


A shared_ptr<base> can safely take ownership of a derived*, even if base does not have a virtual destructor.

However, this only works if shared_ptr knows what the most derived type of the object is when it takes ownership of it. 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:

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. 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:

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.

The magic only works because fb1 is type foobar*, though. 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:

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. 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:

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

Now if the second line throws, f will be properly destructed and will delete the object.

[*] "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.


foo and bar aren't polymorphic classes and therefore this code will most likely result in invalid pointer deallocation.


It is not safe since you are using a C-Style cast in a C++ code.

Do NOT use C-Style cast, use casts such as static_cast, dynamic_cast, const_cast or reinterpret_cast. Plus, no crash does not mean safety.

In fact, just remove the casts in this case.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜