std::weak_ptr assignment with std::make_shared - c++11

I stumbled upon this behaviour when using std::weak_ptr and std::make_shared and I found it a little weird. I am using C++11.
#include <iostream>
#include <memory>
int main()
{
std::weak_ptr<int> weak;
std::shared_ptr<int> shared {std::make_shared<int>(42)};
weak = shared;
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
weak = std::make_shared<int>(23);
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
return 0;
}
The first std::cout prints fine, the second gives me a segfault. I tried looking at the pages of std::weak_ptr and std::shared_ptr on cppreference but I still don't understand why this happens. Having to create a temporary object feels cumbersome to me, is this something that has been addressed in C++14 or is there something I am failing to see?
Thanks!

The weak_ptr can only be dereferenced after locking if a shared_ptr object still exists that's pointing to the same underlying object.
In your first part
std::shared_ptr<int> shared {std::make_shared<int>(42)};
weak = shared;
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
this is indeed the case. In the second part
weak = std::make_shared<int>(23);
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
it is not the case, as the shared_ptr was a temporary object.
What you've encountered here is exactly what weak_ptr was built for - that it be valid only as long as some other shared_ptr points to the same underlying object. That is its purpose:
std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr... If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well.

This is due to the fact that you create a temporary shared pointer and assign it to a weak pointer right away in this line:
weak = std::make_shared<int>(23);
After the assignment operator ends, the temporary shared pointer is destructed, the reference count reaches 0 (since weak pointers do not increase the reference counter) and hence, the resource on the heap is deleted.

Related

How to sink rvalue in a path where it's not used

When a function takes an rvalue reference which it doesn't use in some branches, what should it do with the rvalue to maintain the semantic correctness of it's signature and to be consistent about the ownership of the data. Considering the sample code below:
#include <memory>
#include <list>
#include <iostream>
struct Packet {};
std::list<std::unique_ptr<Packet>> queue;
void EnQueue(bool condition, std::unique_ptr<Packet> &&pkt) {
if (condition) queue.push_back(std::move(pkt));
else /* How to consume the pkt? */;
}
int main()
{
std::unique_ptr<Packet> upkt1(new Packet());
std::unique_ptr<Packet> upkt2(new Packet());
EnQueue(true, std::move(upkt1));
EnQueue(false, std::move(upkt2));
std::cout << "raw ptr1: " << upkt1.get() << std::endl;
std::cout << "raw ptr2: " << upkt2.get() << std::endl;
return 0;
}
The signature of the Enqueue function indicates that it will take ownership of the data passed to it but this is only true if it hits the if path, instead if it hits the else path the function effectively doesn't use the rvalue and the ownership is returned back to the caller, which is illustrated by the fact that upkt2.get is not NULL after returning from the function. The net effect is that the behaviour of EnQueue is inconsistent with it's signature.
The question now is - whether this is an acceptable behaviour or should the EnQueue function be changed to be consistent, if so how?
I see three ways of dealing with this.
Document that after the function exits, "pkt is left in a valid, but unspecified state." That way, the caller cannot assume anything about the parameter afterwards; if they need it cleared no matter what, they can do it explicitly. If they don't, they will not pay for any internal cleanup they would not use.
If you want to make the signature 100% clear on accepting ownership, just take pkt by value instead of rvalue reference (as suggested by #Quentin in comments).
Construct a temporary from pkt:
if (condition) queue.push_back(std::move(pkt));
else auto sink(std::move(pkt));

Why do I need to dereference iterator to smart pointer twice instead of using operator->()?

Suppose I have a following code:
#include <iostream>
#include <deque>
#include <memory>
struct Test
{
int test;
};
int main(int, char**)
{
std::deque<std::unique_ptr<Test>> deque;
deque.push_back(std::unique_ptr<Test>(new Test{10}));
auto start = deque.begin();
std::cout << start->test << std::endl; // <- compilation error
std::cout << (start.operator->())->operator->()->test << std::endl; // <- OK
}
Why is smart-pointer treated as if it would be regular pointer object, although it is not (as far, as I understand)? From what I know, operator->() should recur until it reaches T*.
Here are some related questions on how arrow overloading works and that we need to dereference twice instead of an arrow.
For an iterator it, the expression it->m is equivalent to (*i).m, technically it means that the iterator's operator-> returns a raw pointer to the contained object. In your case it means it returns a raw pointer to the unique_ptr. A final operator-> is applied to that and you end up with a reference to the contained object. This is why no further chaining of operator-> occurs.
The arrow operator is overloaded for unique_ptr. Because you have an iterator, you are dereferencing to a unique_ptr, not the object owned by it. Therefore, you need to dereference twice.
std::cout << (*start)->test << std::endl;
Smart pointer like std::unique_ptr are implemented to store a pointer and behave like a C pointer, while iterators also are pointers themselves.
So why you need to dereference twice? Simply because you have a pointer to pointer to Test.
Its exactly the same as if you have a container of plain pointers:
std::deque<Test*> dq;
dq.push_back(new Test{10});
auto start = dq.begin();
std::cout << (*start)->test << std::endl;

std::unique_ptr<T> without allocating memory on heap

I wrote accidentally a statement like
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff();
instead of
std::unique_ptr<Thing> m_thing(new Thing);
m_thing->DoStuff();
the first example compiles and run, which doesn't make any sense to me because m_thing is not pointing to any object. Here a slightly bigger code example.
#include <iostream>
#include <memory>
class Thing
{
public:
~Thing(){ std::cout << "destructor of class Thing\n"; }
void DoStuff(){ std::cout << "doing stuff\n"; }
};
void Foo()
{
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff(); //why does this work, since i suppose m_thing to be empty?
}
int main()
{
Foo();
std::cout << "after Foo()\n";
std::cin.get();
return 0;
}
Why can the "empty" m_thing unique_ptr invoke the DoStuff()-Method of the Thing-class?
i noticed also, that the destructor of Thing-class never gets invoked when declaring m_thing
with
std::unique_ptr<Thing> m_thing;
instead of
std::unique_ptr<Thing> m_thing(new Thing);
I didn't found any explanation of this behaviour via google, so i hope maybe someone can explain to me what is happening here behind the curtains.
Your program exhibits undefined behavior. "Seems to work" is one possible manifestation of undefined behavior. It's morally equivalent to
Thing* p = NULL;
p->DoStuff();
which I predict would also compile and run. DoStuff is called with NULL for this pointer - but it doesn't actually use this, that's why it doesn't crash and burn as you expect.
DoStuff isn't virtual and doesn't access any members of your object, so you can get away with calling it (I'm pretty sure this is unspecified behavior though). The default constructor for unique_ptr initializes it to nullptr, so it doesn't allocate any memory on its own.
Oh, and the destructor of course doesn't get called because unique_ptr doesn't invoke its deleter on nullptrs.

allocating memory for derived class members based on boost smart pointers in the base class through CRTP

This part of the question provides background information and can be ignored
I am working on a template library which heavily relies on the use of the curiously recurring template pattern. The idea behind the class structure is that the user can either
1). Use predefined classes with standard methods. These classes are very simple leafs of the base class that only provide constructors/destructor, declare the variable members and declare the base class(es) as friend(s). All methods that operate on the variable members of the derived classes are defined in the base class(es).
2). Use the base classes to create his/her own extensions. This method also allows users to introduce their own methods that operate on the same variable members.
Only a single level inheritance is enforced by design.
My question is, primarily, about the clause 2. In the current implementation the user has to define all constructors implicitly (i.e. describe full process of memory allocation for dynamic variable members of the class, etc).
Question
The example below demonstrates an investigation into a possibility to use the CRTP to provide the definition of the allocation of the memory of the heap variables of the derived classes in the base class constructors.
Part of the base class
template<class TLeafType, class MyClass> class sysBaseDiscreteTrajectoryPoint {
...
//one of the base constructors
sysBaseDiscreteTrajectoryPoint(const MyClass& MyClassInstance) {
std::cout << "Base additional constructor called" << std::endl;
std::cout << asLeaf().Point << std::endl;
asLeaf().Point=new MyClass(MyClassInstance);
std::cout << asLeaf().Point << std::endl;
}
TLeafType& asLeaf(void) {
return static_cast<TLeafType&>(*this);
}
...
};
The derived class:
template<class MyClass>
class sysDiscreteTrajectoryPoint: public sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass> {
...
friend class sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass>;
private:
MyClass* Point;
public:
sysDiscreteTrajectoryPoint(const MyClass& MyClassInstance): sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass>(MyClassInstance){
std::cout << "Derived additional constructor called " << std::endl;
std::cout << Point << std::endl;
std::cout << *Point << std::endl;
}
...
}
main:
int a(5);
sysDiscreteTrajectoryPoint<int> A(a);
The code produces the following output:
Base additional constructor called
0x847ff4
0x8737008
Derived additional constructor called
0x8737008
5
Derived destructor called
Base destructor called
The output suggests that the concept may be feasible. However, I have two questions.
1). I would like to ensure that I understand all processes that happen during the execution of the code. In particular, I am interested in the efficiency of the process, as I may need to instantiate a substantial amount of objects from the classes presented above and I would like to understand what happens with Point (are there any hidden redefinitions?)
2). The question is related to the use of the library boost for the definition of smart pointers for the members of the derived class. When I tried replacing the raw pointer with boost::shared_ptr, I received a segmentation fault error when trying to allocate memory for the member of the derived class through the base class. The important sections of the code are shown below.
Part of the base class:
template<class TLeafType, class MyClass> class sysBaseDiscreteTrajectoryPoint {
...
//one of the base constructors
sysBaseDiscreteTrajectoryPoint(const MyClass& MyClassInstance) {
std::cout << "Base additional constructor called" << std::endl;
std::cout << asLeaf().Point << std::endl;
asLeaf().Point.reset(new MyClass(MyClassInstance));
std::cout << asLeaf().Point << std::endl;
}
TLeafType& asLeaf(void) {
return static_cast<TLeafType&>(*this);
}
...
};
Part of the derived class:
template<class MyClass>
class sysDiscreteTrajectoryPoint: public sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass> {
...
friend class sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass>;
private:
boost::shared_ptr<MyClass> Point;
public:
sysDiscreteTrajectoryPoint(const MyClass& MyClassInstance): sysBaseDiscreteTrajectoryPoint<sysDiscreteTrajectoryPoint<MyClass>, MyClass>(MyClassInstance){
std::cout << "Derived additional constructor called " << std::endl;
std::cout << Point << std::endl;
std::cout << *Point << std::endl;
}
...
}
main:
int a(5);
sysDiscreteTrajectoryPoint<int> A(a);
The code produces the following output:
Base additional constructor called
0x28d324
Segmentation fault
I have also tried scoped_ptr. However, it failed at run time but with a different error:
Base additional constructor called
*** glibc detected *** ./TestSystem: free(): invalid pointer: 0x00d3fff4 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x6b961)[0xc4e961]
...
I assume that it is related to the specifics of the operation of boost smart pointers. Does anyone know how to resolve this issue?
The address of the shared_ptr is known at compile time for the reasons given in the above answers, but the shared_ptr itself is still uninitialised because the derived-class constructor has not yet been called, and thus has not had a chance to implicitly call its instance members' constructors, including the default constructor for shared_ptr. Therefore, when you call reset() to assign the shared_ptr, it first tries to release (and possibly delete) the object at whatever spurious address it contains (to avoid leaking an existing referent) before assigning and referencing the new object. That first step, I believe, is what causes the segfault.
If the shared_ptr constructor ran first, it would null its contained raw pointer, preventing the subsequent reset() call from trying to release an object at the spurious address.
Using asLeaf() to access the derived class from the base-class constructor is inherently unsafe for non-POD types because construction is incomplete (the derived class's members are not yet constructed). This is, incidentally, why virtual method calls from a base constructor will never call overrides from more-derived classes - the language explicitly prevents overrides from being called until construction of the whole object is complete because in most cases the state of the whole object is not yet defined.
There may be better solutions for you, but one approach that would work would be to remove that initialization code from the base class's constructor and put it in an init() function that is called explicitly at every instantiation of the derived class. init() can still live in the base class, but it's safer because everything will have been initialized by the time it runs.
Side note: avoid putting small objects in shared_ptr without good reason. You might have a legitimate need for it in this case, but in general I prefer direct aggregation of members to single-owner pointers and single-owner pointers to shared pointers wherever possible because the overhead escalates. Single-owner pointers involve heap allocations, and shared pointers also add to this the cost of counting/tracking owners so that the object can be deleted when unreachable.
How is it possible that you can access Point member belonging to the derived class from base constructor? When the base constructor is being invoked, the derived class part does not exist. Perhaps it works just "by accident".
But it certainly fails with shared_ptr, because you attempt to assign it before it has a chance to get initialized.

const shared_ptr to shared_ptr

How can one convert a shared_ptr that points to a const object to a shared_ptr that points to a non-const object.
I am trying to do the following :
boost::shared_ptr<const A> Ckk(new A(4));
boost::shared_ptr<A> kk=const_cast< boost::shared_ptr<A> > Ckk;
But it does not work.
'boost::const_pointer_cast' will do what you're asking for, but the obligatory second half of the answer is that you probably shouldn't use it. 99% of the time when it seems like you need to cast away the const property of a variable, it means that you have a design flaw. Const is sometimes more than just window dressing and casting it away may lead to unexpected bugs.
Without knowing more details of your situation one can't say for certain. But no discussion of const-cast is complete without mentioning this fact.
use boost::const_pointer_cast, documentation.
the proper way should be this
boost::shared_ptr<A> kk (boost::const_pointer_cast<A>(Ckk));
std::const_cast_pointer makes a second managed pointer. After the cast you have a writable pointer and the original const-pointer. The pointee remains the same. The reference count has been increased by 1.
Note that const_cast is a builtin keyword, but const_pointer_cast is a template function in namespace std.
The writable pointer can then be used to change the value from under the shared_ptr<const T>. IMHO the writable pointer should only persist temporarily on the stack; otherwise there must be a design flaw.
I once wrote a small test program to make this clear to myself which I adapted for this thread:
#include <memory>
#include <iostream>
#include <cassert>
using namespace std;
typedef shared_ptr<int> int_ptr;
typedef shared_ptr<const int> const_int_ptr;
int main(void)
{
const_int_ptr Ckk(new int(1));
assert(Ckk.use_count() == 1);
cout << "Ckk = " << *Ckk << endl;
int_ptr kk = const_pointer_cast<int>(Ckk); // obtain a 2nd reference
*kk = 2; // change value under the const pointer
assert(Ckk.use_count() == 2);
cout << "Ckk = " << *Ckk << endl; // prints 3
}
Under UNIX or Windows/Cygwin, compile with
g++ -std=c++0x -lm const_pointer_cast.cpp

Resources