From cppreference I learn that there is a constructor for std::shared_ptr
:
template< class Y > explicit shared_ptr( Y* ptr );
And I tried a piece of code as follows:
#include <string>
#include <memory>
#include <iostream>
int main(void) {
/// block 1
{
std::shared_ptr<std::string> s1(new std::string("good"));
std::shared_ptr<std::string> s2(s1.get()); /// s2
std::cerr << s2.use_count() << std::endl;
}
/// block 2
{
std::shared_ptr<int> i1(new int(1));
std::shared_ptr<int> i2(i1.get()); /// i2
std::cerr << i2.use_count() << std::endl;
}
return 0;
}
It causes segment fault for block 1 but not for block 2, but both use_count
are 1. The difference I can think about is that that int
is a primitive type while std::string
is managed by allocator.
I read bits/shared_ptr.h
of gcc-4.9
and find that there is a post condition for this constructor:
use_count() == 1 && get() == __p
Should std::shared_ptr
NOT constructed with a raw pointer that has been referenced by another smart pointer? In this sense, is the preferred way to use this constructor as follow?
std::shared_ptr<T>(new T(...));
Does the standard has explicit requirement for this constructor, or this post condition is ONLY for libstdc++
?
Both of these cases are invalid uses of std::shared_ptr
.
You cannot pass the same raw pointer to two std::shared_ptr
constructors and expect well-defined results. Both std::shared_ptr
s will believe that they own that pointer, and will attempt to delete it when they go out of scope.
This is a double free, and is invalid.
If you want to have two std::shared_ptr
s that manage the same object, you can construct one of them with a raw pointer (or, better yet, use std::make_shared
), and then copy construct/assign the second one from the first one. This way the memory will only be deallocated (and the destructor for the object fired) when the last of those std::shared_ptr
s goes out of scope.
The reason you're getting a segmentation fault in the first case, and not the second one, is likely because int
is a trivial type, and therefore you're not looking through a freed pointer to run the destructor of int
, because it doesn't have one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With