segment fault for a simple std::shared_ptr construction case - c++

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
Question 1:
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(...));
Question 2:
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_ptrs 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_ptrs 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_ptrs 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.

This is undefined behavior, we can see this by going to cppreference section for std::shared_ptr constructors says this (emphasis mine):
Constructing a shared_ptr using the raw pointer overload for an object
that is already managed by a shared_ptr leads to undefined behavior,
even if the object is of a type derived from
std::enable_shared_from_this (in other words, raw pointer overloads
assume ownership of the pointed-to object).
Both shared_ptr will attempt to delete the object they believe they now hold sole ownership for. We know this is undefined behavior by going to the draft C++ standard section 3.7.4.2 Deallocation functions which says:
If the argument given to a deallocation function in the standard
library is a pointer that is not the null pointer value (4.10), the
deallocation function shall deallocate the storage referenced by the
pointer, rendering invalid all pointers referring to any part of the
deallocated storage. Indirection through an invalid pointer value and
passing an invalid pointer value to a deallocation function have
undefined behavior. [...]
Ownership can only be shared by using copy construction or copy assignment. The same cppreference page provides a correct example using the copy constructor:
std::cout << "constructor with object\n";
std::shared_ptr<Foo> sh2(new Foo);
std::shared_ptr<Foo> sh3(sh2); // <- using copy construction
An alternative method to creating a shared_ptr is to use std::make_shared, which is safer:
Moreover, code such as f(std::shared_ptr(new int(42)), g()) can
cause a memory leak if g throws an exception because g() may be called
after new int(42) and before the constructor of shared_ptr. This
doesn't occur in f(std::make_shared(42), g()), since two function
calls are never interleaved.

Related

Why does the impl of shared_ptr ref count hold a pointer to the actual pointed type?

This was motivated by an interview question:
shared_ptr<void> p(new Foo());
Will the destructor of Foo get called once p goes out of scope?
It turns out it does, I had to look at the implementation of shared_ptr in GCC 1, and find out that apparently the control block holds a pointer to the actual type (Foo) and a pointer to the destructor that gets invoked when the ref count reaches 0.
1: Sorry I am on my phone I cannot copy the link to the impl.
But I am still wondering: why? Why is it needed? Is there anything I am missing from the standard?
On the other hand, the line above doesn't compile with unique_ptr because obviously there's no ref count in that case.
A std::shared_ptr<T> instance itself must keep track of the pointer to return when .get() is called. This is always of type T*, except when T is an array, in which case it is of type std::remove_extent_t<T>* (for example, std::shared_ptr<int[]>::get() returns int*).
Also, when a std::shared_ptr<T> is destroyed, it has to check whether it is the last std::shared_ptr instance referring to its control block. If so, it must execute the deleter. In order for this to work, the control block must keep track of the pointer to pass to the deleter. It is not necessarily of the type T* or std::remove_extent_t<T>*.
The reason why these are not the same is that, for example, code like the following should work:
struct S {
int member;
int other_member;
~S();
};
void foo(std::shared_ptr<int>);
int main() {
std::shared_ptr<S> sp = std::make_shared<S>();
std::shared_ptr<int> ip(sp, &sp->member);
foo(std::move(ip));
}
Here, sp owns an object of type S and also points to the same object. The function foo takes a std::shared_ptr<int> because it is part of some API that needs an int object that will remain alive for as long as the API isn't done with it (but the caller can also keep it alive for longer, if they want). The foo API doesn't care whether the int that you give it is part of some larger object; it just cares that the int will not be destroyed while it is holding on to it. So, we can create a std::shared_ptr<int> named ip, which points to sp->member, and pass that to foo. Now, this int object can only survive as long as the enclosing S object is alive. It follows that ip must, as long as it is alive, keep the entire S object alive. We could now call sp.reset() but the S object must remain alive, since there is still a shared_ptr referring to it. Finally, when ip is destroyed, it must destroy the entire S object, not just the int that it, itself, points to. Thus, it is not enough for the std::shared_ptr<int> instance ip to store a int* (which will be returned when .get() is called); the control block that it points to also has to store the S* to pass to the deleter.
For the same reason, your code will call the Foo destructor even though it is a std::shared_ptr<void> that is carrying out the destruction.
You asked: "Is there anything I am missing from the standard?" By this I assume you are asking whether the standard requires this behaviour and if so, where in the standard is it specified? The answer is yes. The standard specifies that a std::shared_ptr<T> stores a pointer and may also own a pointer; these two pointers need not be the same. In particular, [util.smartptr.shared.const]/14 describes constructors that "[construct] a shared_ptr instance that stores p and shares ownership with the initial value of r" (emphasis mine). The shared_ptr instance thus created may own a pointer that is different from the one it stores. However, when it is destroyed, [util.smartptr.shared.dest]/1 applies: if this is the last instance, the owned pointer is deleted (not the stored one).
I assume that for this code the answer is trivial:
shared_ptr<Foo> p(new Foo());
Every call to new must be balanced by a call to delete. Every constructed object must be destructed too. So if
shared_ptr<void> p(new Foo());
would not call ~Foo() that would be rather surprising and would cause resource leaks, dangling pointers or any number of UB caused by the destructor not being called.
For me the bigger question is: Why does that compile at all? The shared_ptr has the wrong type so it shouldn't be able to call the right destructor and that should not compile (like unique_ptr fails).
The reason for that is this little bit of genius I believe:
template< class Y > shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
template< class Y > shared_ptr( shared_ptr<Y>&& r, element_type* ptr ) noexcept;
You can create a shared pointer pointing at a member of a larger object, which will keep the larger object alive as long as the pointer to the member exists.
For this feature to work the shared_ptr and the control block of the shared_ptr both have a pointer and they can have different types. The control block always points to the object while the shared_ptr points to the member. When you normaly create a shared_ptr they happen to be the same type and point to the same address. But apparently that isn't always the case.
This also allows making a shared_ptr<void> with the control block pointing at a Foo. Here both point to the same address but have different type. The control block know the type of the original object and what destructor to call in the end.
How does that work? The shared_ptr and control block can have different types of pointers and that allows for these copy constructors:
template< class Y > shared_ptr( const shared_ptr<Y>& r ) noexcept;
template< class Y > shared_ptr( shared_ptr<Y>&& r ) noexcept;
As long as Y* is convertible / compatible with T* you can change the type of the shared_ptr during copy construction. The given code actually turns into this:
shared_ptr<void> p(shared_ptr<Foo>(new Foo()));
It creates a temporary shared_ptr<Foo> with the control block having a Foo* and then p reuses the same control block.
std::shared_ptr::shared_ptr - cppreference.com
constexpr shared_ptr() noexcept;
(1)
constexpr shared_ptr( std::nullptr_t ) noexcept;
(2)
template< class Y > explicit shared_ptr( Y* ptr );
(3)
.....
...
....
3-7) Constructs a shared_ptr with ptr as the pointer to the managed object.
For (3-4,6), Y* must be convertible to T*.
(until C++17)
If T is an array type U[N], (3-4,6) do not participate in overload resolution if Y(*)[N] is not convertible to T*. If T is an array type U[], (3-4,6) do not participate in overload resolution if Y(*)[] is not convertible to T*. Otherwise, (3-4,6) do not participate in overload resolution if Y* is not convertible to T*.
(since C++17)
Additionally:
Uses the delete-expression delete ptr if T is not an array type; delete[] ptr if T is an array type (since C++17) as the deleter. Y must be a complete type. The delete expression must be well-formed, have well-defined behavior and not throw any exceptions. This constructor additionally does not participate in overload resolution if the delete expression is not well-formed. (since C++17)
So basically third form is used.
Also data holding reference counters (strong and weak) holds also information about destructor of the object. This (3) form of constructor fetches this information.
Note that std::unique_ptr by default do not hold such information and so it will fail in this scenario (fails to compile).

C++ multiple unique pointers from same raw pointer

Consider my code below. My understanding of unique pointers was that only one unique pointer can be used to reference one variable or object. In my code I have more than one unique_ptr accessing the same variable.
It's obviously not the correct way to use smart pointers i know, in that the pointer should have complete ownership from creation. But still, why is this valid and not having a compilation error? Thanks.
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int val = 0;
int* valPtr = &val;
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(valPtr);
*uniquePtr1 = 10;
*uniquePtr2 = 20;
return 0;
}
But still, why is this valid
It is not valid! It's undefined behaviour, because the destructor of std::unique_ptr will free an object with automatic storage duration.
Practically, your program tries to destroy the int object three times. First through uniquePtr2, then through uniquePtr1, and then through val itself.
and not having a compilation error?
Because such errors are not generally detectable at compile time:
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(function_with_runtime_input());
In this example, function_with_runtime_input() may perform a lot of complicated runtime operations which eventually return a pointer to the same object valPtr points to.
If you use std::unique_ptr correctly, then you will almost always use std::make_unique, which prevents such errors.
Just an addition to Christian Hackl's excellent answer:
std::unique_ptr was introduced to ensure RAII for pointers; this means, in opposite to raw pointers you don't have to take care about destruction yourself anymore. The whole management of the raw pointer is done by the smart pointer. Leaks caused by a forgotten delete can not happen anymore.
If a std::unique_ptr would only allow to be created by std::make_unique, it would be absolutely safe regarding allocation and deallocation, and of course that would be also detectable during compile time.
But that's not the case: std::unique_ptr is also constructible with a raw pointer. The reason is, that being able to be constructed with a hard pointer makes a std::unique_ptr much more useful. If this would not be possible, e.g. the pointer returned by Christian Hackl's function_with_runtime_input() would not be possible to integrate into a modern RAII environment, you would have to take care of destruction yourself.
Of course the downside with this is that errors like yours can happen: To forget destruction is not possible with std::unique_ptr, but erroneous multiple destructions are always possible (and impossible to track by the compiler, as C.H. already said), if you created it with a raw pointer constructor argument. Always be aware that std::unique_ptr logically takes "ownership" of the raw pointer - what means, that no one else may delete the pointer except the one std::unique_ptr itself.
As rules of thumb it can be said:
Always create a std::unique_ptr with std::make_unique if possible.
If it needs to be constructed with a raw pointer, never touch the raw pointer after creating the std::unique_ptr with it.
Always be aware, that the std::unique_ptr takes ownership of the supplied raw pointer
Only supply raw pointers to the heap. NEVER use raw pointers which point to local
stack variables (because they will be unavoidably destroyed automatically,
like valin your example).
Create a std::unique_ptr only with raw pointers, which were created by new, if possible.
If the std::unique_ptr needs to be constructed with a raw pointer, which was created by something else than new, add a custom deleter to the std::unique_ptr, which matches the hard pointer creator. An example are image pointers in the (C based) FreeImage library, which always have to be destroyed by FreeImage_Unload()
Some examples to these rules:
// Safe
std::unique_ptr<int> p = std::make_unique<int>();
// Safe, but not advisable. No accessible raw pointer exists, but should use make_unique.
std::unique_ptr<int> p(new int());
// Handle with care. No accessible raw pointer exists, but it has to be sure
// that function_with_runtime_input() allocates the raw pointer with 'new'
std::unique_ptr<int> p( function_with_runtime_input() );
// Safe. No accessible raw pointer exists,
// the raw pointer is created by a library, and has a custom
// deleter to match the library's requirements
struct FreeImageDeleter {
void operator() (FIBITMAP* _moribund) { FreeImage_Unload(_moribund); }
};
std::unique_ptr<FIBITMAP,FreeImageDeleter> p( FreeImage_Load(...) );
// Dangerous. Your class method gets a raw pointer
// as a parameter. It can not control what happens
// with this raw pointer after the call to MyClass::setMySomething()
// - if the caller deletes it, your'e lost.
void MyClass::setMySomething( MySomething* something ) {
// m_mySomethingP is a member std::unique_ptr<Something>
m_mySomethingP = std::move( std::unique_ptr<Something>( something ));
}
// Dangerous. A raw pointer variable exists, which might be erroneously
// deleted multiple times or assigned to a std::unique_ptr multiple times.
// Don't touch iPtr after these lines!
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
// Wrong (Undefined behaviour) and a direct consequence of the dangerous declaration above.
// A raw pointer is assigned to a std::unique_ptr<int> twice, which means
// that it will be attempted to delete it twice.
// This couldn't have happened if iPtr wouldn't have existed in the first
// place, like shown in the 'safe' examples.
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
std::unique_ptr<int> p2(iPtr);
// Wrong. (Undefined behaviour)
// An unique pointer gets assigned a raw pointer to a stack variable.
// Erroneous double destruction is the consequence
int val;
int* valPtr = &val;
std::unique_ptr<int> p(valPtr);
This example of code is a bit artificial. unique_ptr is not usually initialized this way in real world code. Use std::make_unique or initialize unique_ptr without storing raw pointer in a variable:
unique_ptr <int> uniquePtr2(new int);

Does shared_ptr still own its object when calling the deleter?

I have a std::shared_ptr with a custom deleter and in that deleter, I would like to take a temporary copy of the original std::shared_ptr. Expressed in code form:
struct Foo : public std::enable_shared_from_this<Foo>
{};
void deleter(Foo *f)
{
{
std::shared_ptr<Foo> tmp = f->shared_from_this(); // Line A
}
delete f;
}
int main()
{
std::shared_ptr<Foo> foo(new Foo, &deleter);
}
My question is: on line A, can anything be said about the call of shared_from_this()? Is it legal? If so, does the standard say anything about its return value? If we replace enable_shared_from_this with a different weak_ptr or global reference to foo, will the answer be the same?
Clang with libc++ and gcc with libstdc++ both produce code which terminates on a bad_weak_ptr exception, but I can't seem to trace this as required by the standard. Is this implementation-specific, or am I missing a rule?
All the relevant rules I found (quoting C++11):
20.7.2.2.2 shared_ptr destructor
1 ... if *this owns an object p and a deleter d, d(p) is called
2 [Note: ... Since the destruction of *this decreases the number of instances that share ownership with *this
by one, after *this has been destroyed all shared_ptr instances that shared ownership with *this will
report a use_count() that is one less than its previous value. —end note]
20.7.2.2.5 shared_ptr observers
7 use_count Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0
when *this is empty.
To me, it seems it's not clear whether the decrement of use_count happens before or after the call of the deleter. Is getting bad_weak_ptr a reliable result, or is this simply unspecified?
Note that I am intentionally avoiding a situation where a pointer like tmp in my example code would outlive the deleter execution.
consider
[c++14-12.4-15]Once a destructor is invoked for an object, the object no longer exists;
and
[c++14-20.8.2.4-7]shared_from_this()[...]Requires: enable_shared_from_this shall be an accessible base class of T. *this shall be a subobject of an object t of type T. There shall be at least one shared_ptr instance p that owns &t.
so, considering that the deleter is invoked by the shared_ptr destructor, calling shared_from_this() in the deleter of the last shared_ptr owning it results in undefined behaviour.
EDIT: as pointed out by YSC, in C++17 shared_from_this() is required to behave as the corresponding weak_ptr conversion call. This complicates matters though, because it's not clear what weak_ptr::expired() should return at deleter call ... anyway, taking the quoted 20.7.2.2.2 note literally, a bad_weak_ptr should be raised in this case.

`weak_ptr::expired` behavior in the dtor of the object

Consider the following code:
#include <iostream>
#include <memory>
using namespace std;
class T;
std::weak_ptr<T> wptr;
class T
{
public:
T() { }
~T() {
std::cout << "in dtor" << std::endl;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
};
int main() {
{
auto ptr = std::make_shared<T>();
wptr = ptr;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
return 0;
}
In this code, I was trying to find out if weak_ptrs are expired in the objects destruction phase. It seems so. The output is:
not expired
in dtor
expired
I used gcc-5.1 with ideone.
Now, I have another problem. I couldn't find any documentation stating that this is the standard behavior. Is it guaranteed to work this way, always?
Now, I have another problem. I couldn't find any documentation stating that this is the standard behavior. Is it guaranteed to work this way, always?
No. Indeed, it's underspecified in the standard, as raised by LWG issue 2751.
The C++14 standard contains no language that guarantees the deleter run by a shared_ptr will see all associated weak_ptr instances as expired. For example, the standard doesn't appear to guarantee that the assertion in the following snippet won't fire:
std::weak_ptr<Foo> weak;
std::shared_ptr<Foo> strong{
new Foo,
[&weak] (Foo* f) {
assert(weak.expired());
delete f;
},
};
weak = strong;
strong.reset();
It seems clear that the intent is that associated weak_ptrs are expired, because otherwise shared_ptr deleters could resurrect a reference to an object that is being deleted.
Suggested fix: 23.11.3.2 [util.smartptr.shared.dest] should specify that the decrease in use_count() caused by the destructor is sequenced before the call to the deleter or the call to delete p.
The current wording for ~shared_ptr() as linked above simply states that the deleter is invoked, with a non-normative note that the number of instances that share ownership is decreased.
While the intent is probably that weak.expired() when the deleter is called, it's questionable to rely on this. It's really only reasonable to state with confidence that the shared_ptr no longer shares ownership after it's been destroyed - asking that question during destruction is a bit odd.
Using make_shared like that will create an object with the default constructor you provided.
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
Constructs an object of type T and wraps it in a std::shared_ptr
using args as the parameter list for the constructor of T. The object
is constructed as if by the expression (std::make_shared)
After the anonymous scope in the main. The shared ptr will be deleted.
The object is destroyed and its memory deallocated when either of the
following happens:
the last remaining shared_ptr owning the object is destroyed;
(std::shared_ptr)
.
The destructor of shared_ptr decrements the number of shared owners of
the control block. If that counter reaches zero, the control block
calls the destructor of the managed object. The control block does not
deallocate itself until the std::weak_ptr counter reaches zero as
well. std::shared_ptr Implementation notes
This means that your object will call its destructor after the destruction of the last shared ptr has started.
The output:
not expired
in dtor
expired
is the expected behavior.
Not the standard itself but:
http://en.cppreference.com/w/cpp/memory/weak_ptr/expired
Checks whether the managed object has already been deleted. Equivalent
to use_count() == 0.
So it becomes a question of weather use_count is set to 0 before or after deletion. Now there's a not on this in a draft of the standard:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf [page 566 20.9.2.2.2]
~shared_ptr();
Effects:
If *this is empty or shares ownership with another shared_ptr instance (use_count() > 1), there are no side effects.
Otherwise, if *this owns an object p and a deleter d, d(p) is called.
Otherwise, *this owns a pointer p, and delete p is called.
[Note: Since the destruction of *this decreases the number of
instances that share ownership with *this by one, after *this has
been destroyed all shared_ptr instances that shared ownership with
*this will report a use_count()that is one less than its previous
value. — end note]
A weak_ptr expires when there are no more shared_ptrs referring to the object.
When (immediately after) the last shared_ptr stops referring to the object it's destroyed.
At this point there are no shared_ptrs referring to it, so any weak_ptr has expired.
The object's destructor is now invoked and if it has separate storage (i.e. wasn't created with make_shared) its storage is deallocated.
The control block, where the reference count and raw pointer and delete function are stored, persists if there are any weak_ptrs referring to it. When the last weak_ptr stops referring to it, also the control block is destroyed and deallocated. I.e., shared_ptr instances keep the object itself alive, along with its control block, while weak_ptr instances keep the control block alive.

Why does boost not have a make_scoped()?

Boost's make_shared() function promises to be exception-safe while attempting to create a shared_ptr.
Why is there no make_scoped() equivalent? Is there a common best practice?
Here's a code example from the boost::scoped_ptr documentation that seems unsafe to me:
boost::scoped_ptr<Shoe> x(new Shoe);
This line of code will do these three things in order:
Allocate heap memory for Shoe
Call the constructor for Shoe
Call the constructor for boost::scoped_ptr<Shoe>
If the constructor for Shoe throws an exception, memory will be leaked. (see R. Martinho Fernandes answer) The scoped_ptr won't handle the deallocation because it hasn't been constructed yet.
Is this an oversight? Or is there a solution that I've failed to notice?
scoped_ptr predates move semantics and is noncopyable by design. Thus, make_scoped would be impossible to implement because in order to return an object from a function, its type must either be movable or copyable.
If the constructor fails, no memory is leaked. That's part of the semantics of new, no smart pointers involved:
struct Foo { Foo() { throw 23; } };
new Foo(); // no memory leaked
The added exception safety provided by make_shared comes from when you're initializing two shared_ptrs in an expression and the two initializations are not sequenced, as is the case in function call arguments:
struct Bar {
Bar(bool fail) {
if(fail) throw 17;
}
}
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false)));
Since there is no sequencing between the evaluations of new Bar(true), shared_ptr<Bar>(new Bar(true)), new Bar(false) and shared_ptr<Bar>(new Bar(false)), the following could happen:
new Bar(false) is evaluated and succeeds: memory is allocated;
new Bar(true) is evaluated and fails: it doesn't leak memory resulting from this evaluation;
No shared_ptr was constructed at this time, and so the memory allocated in #1 is now leaked.
If Shoe throws then Shoe isn't constructed so there is nothing scoped_ptr can really do. No?
The scoped_ptr x is on the stack and will get cleaned up on scope exit.