C++ - shared_ptr of abstract class - c++

I have the following code:
#include <string>
#include <queue>
#include <thread>
#include <iostream>
using namespace std;
class MsgType {
public:
virtual string getData() const = 0;
static MsgType* getMsg();
};
class Msg1 : public MsgType {
string getData() const override final {
return "Msg1";
}
};
class Msg2 : public MsgType {
string getData() const override final {
return "Msg2";
}
};
queue<shared_ptr<MsgType>> allMsgs;
MsgType* MsgType::getMsg() {
shared_ptr<MsgType> msg_sp = nullptr;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
cout << "[in the method] " << mt->getData() << endl;
return mt;
} else {
return nullptr;
}
}
int main() {
MsgType* msg1 = new Msg1();
MsgType* msg2 = new Msg2();
shared_ptr<MsgType> msg;
msg.reset(msg1);
allMsgs.push(msg);
msg.reset(msg2);
allMsgs.push(msg);
MsgType* tryGetMsg = MsgType::getMsg();
cout << "[out of the method] " << tryGetMsg->getData() << endl;
}
In the MsgType::getMsg() method I can see the output, but in the main() I can't. I belive that it's trying to call MsgType::getData() which is virtual.
How can I get the MsgType outside of this method, in a way that I can access the derived class' methods?
Thanks!

The immediate fix is to just return a shared_ptr from getMsg:
shared_ptr<MsgType> MsgType::getMsg() {
shared_ptr<MsgType> msg_sp;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
cout << "[in the method] " << msg_sp->getData() << endl;
}
return msg_sp;
}
and stop converting needlessly between smart and raw pointers.
The message object must be kept alive until the caller has finished using it. Since you're using shared_ptr to manage the object lifetime, you need a shared_ptr to continue existing as long as you want to use the object.
In general, mixing raw and smart pointers to the same objects is risky, because the smart pointers can only track the references they know about: that is, shared_ptr has to know everywhere a pointer to the object is being shared. It can only do this if every one of those pointers is a shared_ptr.
Note also that the easy way to diagnose object lifetime problems is to write a destructor that logs something. This brings us on to the second problem: in order for MsgType to be a suitable abstract base class here, it needs a virtual destructor.
Without that, the shared_ptr will try to destroy your object when the refcount becomes zero, but be unable (in general) to do so correctly.
class MsgType {
public:
virtual ~MsgType() {}
virtual string getData() const = 0;
};
Veering finally into code review, I intentionally omitted getMsg above.
Having a class static method to access a global queue is just weird. If you want to keep that layout, the allMsgs queue should probably be class static as well.
Instead, it's probably better to just keep a msg_queue object wherever you actually need it, with no statics or globals.

Here:
MsgType* MsgType::getMsg() {
shared_ptr<MsgType> msg_sp = nullptr;
if (allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
cout << "[in the method] " << mt->getData() << endl;
return mt;
} else {
return nullptr;
}
}
When allMsgs is not empty you you copy front then pop. At that moment there is a single shared_ptr managing that object: msg_sp. Then you retrieve a raw pointer via get and return that, but when the function returns the use-count decrements to 0 and the managed object is destroyed. The returned pointer is invalid.
I find your mixing of raw and shared_ptr a little confusing. When you have a shared_ptr managing the lifetime of the object then you cannot first get a raw pointer, then let the shared_ptr destroy the managed object and still use the raw pointer. You need to properly transfer ownership when you don't want the shared pointer to destroy the managed object.

I don't know why you are mixing std::shared_ptr and C-style pointers this way, but let's ignore this and assume it's just as an exercise.
Having a look at the bottom half of your code (slightly reduced), we have this:
std::queue<std::shared_ptr<MsgType>> allMsgs;
MsgType* MsgType::getMsg();
int main() {
MsgType* msg1 = new Msg1();
std::shared_ptr<MsgType> msg;
msg.reset(msg1); // <--- 1. here, msg1 is owned by msg
allMsgs.push(msg); // <--- 2. now, msg1 is also owned by allMsgs
msg.reset(); // <--- 3. msg1 only owned by allMsgs
MsgType* tryGetMsg = MsgType::getMsg(); // <--- see below : nobody keeping msg1 alive!
std::cout << "[out of the method] " << tryGetMsg->getData() << std::endl;
}
MsgType* MsgType::getMsg() {
std::shared_ptr<MsgType> msg_sp = nullptr;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front(); // <--- 4. msg1 owned by msg_sp & allMsgs
allMsgs.pop(); // <--- 5. msg1 owned by msg_sp only
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
std::cout << "[in the method] " << mt->getData() << std::endl;
return mt;
} else {
return nullptr;
}
} // <--- 6. msg_sp destroyed... oh oh... msg1 dead :)
As as small addition, you can construct a shared base class pointer directly from a derived one, e.g.
auto msg_sp = std::shared_ptr<MsgType>(std::make_shared<Msg1>());

Related

How to delete an Object whose associating use_count is bigger than 1?

I have an Object with multiple shared_ptrs pointing to it, and its reference count use_count in the associating control block is bigger than 1.
Now, I want to deconstruct the Object, but I do not know where are all those shared_ptrs, so I cannot find and deconstruct them before I deconstruct the Object.
If I just deconstruct the Object, it will make those shared_ptrs become dangling. Therefore, under this situation, how to delete the Object with use_count bigger than 1 but have no idea about all its shared_ptrs?
Thanks for any suggestions!
If you have access to code of Object class and can modify it then you can do following steps (you may jump straight away to final code afterwards):
Create special structure Fields that contains all fields of original Object.
Store Fields as heap-allocated pointer field p_.
In original Object class make all original fields as references pointing to fields of Fields heap allocated object.
Add destroyed_ bool flag that marks that Object was already destroyed. This flag becomes true after first call of destructor.
In every method check that destroyed_ is not true, otherwise throw an exception. Because NONE of methods can be used when object is already destroyed. You may also just show a message with some error instead of throwing exception and return from method without doing anything. Up to you how to handle this error.
Inside destructor on first call make all cleanup as usual. And mark destroyed_ as true. Second call to destructor should just silently exit due to destroyed_ being already true.
All copy constructors and assignment operators should be implemented as usual. Example in code below.
To delete object before all shared pointers are freed just call ptr->~Object(); destructor, here ptr is any shared pointer, or use a convenience function std::destroy_at, like this std::destroy_at(ptr.get());.
In code below if last DoSomething() is not called (try to comment it out) then program finishes without exception, although warning is shown about calling destructor second time.
Try it online!
#include <iostream>
#include <memory>
class Object {
public:
Object()
: p_(new Fields{}), f0_(p_->f0_), f1_(p_->f1_) {}
Object(Object const & o)
: p_(new Fields{}), f0_(o.f0_), f1_(o.f1_) {}
Object & operator = (Object const & o) {
f0_ = o.f0_;
f1_ = o.f1_;
return *this;
}
void DoSomething() {
if (destroyed_)
throw std::runtime_error("Object already destroyed!");
f0_ += 1;
f1_ += std::to_string(f0_) + " ";
std::cout << "DoSomething: '" << f1_ << "'" << std::endl;
}
~Object() {
if (destroyed_) {
std::cout << "Called destructor of destroyed object..."
<< std::endl;
return;
}
// Process fields cleanup here...
delete p_;
p_ = nullptr;
destroyed_ = true;
}
private:
struct Fields {
int f0_ = 0;
std::string f1_;
};
Fields * p_ = nullptr;
bool destroyed_ = false;
int & f0_;
std::string & f1_;
};
int main() {
try {
std::shared_ptr<Object> o0 = std::make_shared<Object>();
{
std::shared_ptr<Object> o1 = o0;
o1->DoSomething();
o1->DoSomething();
// Call destructor when you don't need object.
// Even if some shared_ptrs still use it.
o1->~Object();
}
o0->DoSomething();
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Output:
DoSomething: '1 '
DoSomething: '1 2 '
Called destructor of destroyed object...
Exception: Object already destroyed!
Similar code to above can be also implemented using C++17 std::optional instead of heap pointer, this solution is even better because it doesn't use any heap allocation, all fields are located inside object's body (i.e. stack allocation).
Try it online!
#include <iostream>
#include <memory>
#include <optional>
class Object {
public:
Object()
: p_(Fields{}), f0_(p_->f0_), f1_(p_->f1_) {}
Object(Object const & o)
: p_(Fields{}), f0_(o.f0_), f1_(o.f1_) {}
Object & operator = (Object const & o) {
f0_ = o.f0_;
f1_ = o.f1_;
return *this;
}
void DoSomething() {
if (destroyed_)
throw std::runtime_error("Object already destroyed!");
f0_ += 1;
f1_ += std::to_string(f0_) + " ";
std::cout << "DoSomething: '" << f1_ << "'" << std::endl;
}
~Object() {
if (destroyed_) {
std::cout << "Called destructor of destroyed object..."
<< std::endl;
return;
}
// Process fields cleanup here...
p_ = std::nullopt;
destroyed_ = true;
}
private:
struct Fields {
int f0_ = 0;
std::string f1_;
};
std::optional<Fields> p_;
bool destroyed_ = false;
int & f0_;
std::string & f1_;
};
int main() {
try {
std::shared_ptr<Object> o0 = std::make_shared<Object>();
{
std::shared_ptr<Object> o1 = o0;
o1->DoSomething();
o1->DoSomething();
// Call destructor when you don't need object.
// Even if some shared_ptrs still use it.
o1->~Object();
}
o0->DoSomething();
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Output:
DoSomething: '1 '
DoSomething: '1 2 '
Called destructor of destroyed object...
Exception: Object already destroyed!
How to delete an Object whose associating use_count is bigger than 1?
By reducing the use count to 0. This can be achieved by destroying or reassigning the shared pointers that currently point to the object.
but I do not know where are all those shared_ptrs
Then you must solve the problem that prevents you from knowing all those pointers.
Or, you could consider that perhaps there is a reason why those pointers exist, and that perhaps the object isn't supposed to be deleted yet, since it's apparently being used by some part of the program.

Implicit Conversion of Class

#include <iostream>
using namespace std;
class temp
{
public:
temp()
{
std::cout << "Constructor created." << std::endl;
}
~temp()
{
std::cout << "Deconstructor called." << std::endl;
}
};
class scopedptr
{
private:
temp* ptr;
public:
scopedptr(temp* p)
{
ptr = p;
std::cout << "scoped" << std::endl;
}
~scopedptr()
{
delete ptr;
}
};
int main()
{
{
scopedptr a = new temp();
}
}
Most of the code above is not relevant but I wrote it so that there is a background to my question.
My question resides inside the main function, I know the line "scopedptr a = new temp();" will work, my doubt is the what is happening with the object a, is it associated with the class scopedptr or the temp class.
This code does not have many variables but what if there are multiple variables inside both the classes, will object a be able to call methods from class scopedptr or class temp or both.
I'm literally confused, what's happening with the object? which class is its type???
In the line
scopedptr a = new temp();
type of a is explicitly specified as scopedptr. Any usage of a must correspond to the type scopedptr.
When in doubt, simplify.
temp* temp_ptr = new temp();
scopedptr a{temp_ptr};
Then, there is less scope for confusion.
a is a scopedptr with an owning pointer to a temp.
will object a be able to call methods from class scopedptr or class temp or both
To be able to treat it as a smart pointer, you'd usually add member functions, deferencing the owned pointer:
class scopedptr {
public:
temp* operator->() { return ptr; }
temp& operator*() { return *ptr; }
};
You can now do a->func(); to call a function in the temp object.
Also look into the Rule of 5 for safe handling of the owned pointer.
Demo

enable_shared_from_this Vs Direct Assignment

Why should I use enable_shared_from_this as I can get the same effect via plain assignment also.
struct A : std::enable_shared_from_this<A> {
std::shared_ptr<A> getptr() {
return shared_from_this();
}
};
int main () {
// What is the differentce between this code
std::shared_ptr<A> p1 = make_shared<A>();
std::shared_ptr<A> p2 = p1->getptr();
// Vs this
std::shared_ptr<A> p1 = make_shared<A>();
std::shared_ptr<A> p2 = p1;
}
Because you can't get the "same" effect", at least not the one you may be thinking of.
There is no difference in the posted code methodologies, precisely because A inherits from std::enable_shared_from_this<A>. Both p1 and p2 are shared_ptr objects referring to the same concrete object (assuming only one of those sections is compiled for your tests, else you error on id name reuse).
std::enable_shared_from_this<T> allows you to acquire a std::shared_ptr<T> from some object, formally managed by some preexisting std::shared_ptr<T> of type T or derivative thereof, in locations where you have no std::shared_ptr<T> to the object to otherwise acquire, but need one for one reason or another. For example:
#include <iostream>
#include <memory>
struct A;
void foo(std::shared_ptr<A> arg)
{
}
struct A : std::enable_shared_from_this<A>
{
void method()
{
foo(shared_from_this());
}
};
int main ()
{
auto a = std::make_shared<A>();
a->method();
}
In the above example, foo requires a std::shared_ptr<A> as a parameter. From the body of A::method() no such mechanism exists without std::enable_shared_from_this<A> as a base. Without the std::enabled_shared_from_this<T> base, you would have to provide an alternative mechanism for passing the a shared pointer down the call chain until it reached foo. In short it would look something like this:
#include <iostream>
#include <memory>
struct A;
void foo(std::shared_ptr<A> arg)
{
}
struct A
{
void method(std::shared_ptr<A> me)
{
foo(me);
}
};
int main ()
{
std::shared_ptr<A> a = std::make_shared<A>();
a->method(a);
}
which is obviously dreadful and hideous. Further, there is no guarantee me in method is actually a std::shared_ptr<T> of this. Thus the standards committee blessed us with std::enable_shared_from_this<T>.
It's probably worth mentioning what shared_from_this is 'for'.
The most common use case is to 'keep myself alive' while some asynchronous process is running. A good example of this would be a completion handler, another would be a callback on 'this' when this is controlled by a shared_ptr.
for example:
#include <memory>
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std::literals;
template<class Handler>
void long_process_with_completion_handler(Handler done)
{
std::thread([done] {
std::cout << "long process starts" << std::endl;
std::this_thread::sleep_for(2000ms);
done();
}).detach();
}
struct controller : std::enable_shared_from_this<controller>
{
auto get_lock() const {
return std::unique_lock<std::mutex>(_mutex);
}
void start() {
long_process_with_completion_handler([self = shared_from_this()] {
auto lock = self->get_lock();
std::cout << "all complete" << std::endl;
});
}
mutable std::mutex _mutex;
};
int main()
{
std::condition_variable controller_done;
std::mutex done_mutex;
bool is_controller_done = 0;
// make shared controller
// start its processing
auto pcontroller = std::shared_ptr<controller>{ new controller,
[&](auto*p) {
delete p;
auto lock = std::unique_lock<std::mutex>(done_mutex);
is_controller_done = true;
std::cout << "controller destroyed" << std::endl;
lock.unlock();
controller_done.notify_all();
}};
pcontroller->start();
// destroy the controlling pointer. but our controller is still running...
pcontroller.reset();
auto lock = std::unique_lock<std::mutex>(done_mutex);
controller_done.wait(lock, [&]{ return is_controller_done;});
std::cout << "program ends" << std::endl;
}
The shared-from-this functionality enables you to obtain a shared_ptr to a shared_ptr-managed object when all you have is a raw pointer or a reference.
Just creating a shared_ptr directly from the raw pointer would create a new, unrelated reference counter.
The use case of enable_shared_from_this and shared_from_this is clear, and yet I tend to say that in most use cases it can be dropped in favor of a static method that gets a shared_ptr and then creates a new shared_ptr from it (in a very similar manner to the approach suggested by the OP, but with a static method to support the creation of the new shared_ptr).
The advantage of the static method approach is that you won't fall in the bug of trying to get shared_from_this when there is no underlying shared_ptr for this instance, resulting with bad_weak_ptr.
The disadvantage is that the API is implicitly asking the caller to come with a shared_ptr, so if the caller has just a raw pointer to an instance he can't use it (the caller may create a shared_ptr from the raw pointer and call the method, but how can he tell if the original raw pointer was not managed already by a shared_ptr?). On the other hand, if the user has in hand a unique_ptr he should be positively sure that turning it to shared_ptr in order to call the static method should be fine.
In a way the advantage and disadvantage are two sides of the same coin.
I would prefer in most cases to require the API to work with shared_ptr (it already depends on that in a way) rather than allowing working with any kind of a pointer, with the hope that there is a managed shared_ptr for it. This goes well with the advice of having APIs that cannot be easily used in a wrong way.
Here is the code presented by #RichardHodges (great example!) using the static method approach instead of using enable_shared_from_this:
// code based on Richard Hodges example
template<class Handler>
void long_process_with_completion_handler(Handler done) {
std::thread([done] {
std::cout << "long process starts" << std::endl;
std::this_thread::sleep_for(2000ms);
done();
}).detach();
}
// without the need to inherit from std::enable_shared_from_this
struct Controller {
auto get_lock() const {
return std::unique_lock<std::mutex>(_mutex);
}
static void start(std::shared_ptr<Controller>& pcontroller) {
long_process_with_completion_handler(
[self = std::shared_ptr<Controller>(pcontroller)] {
auto lock = self->get_lock();
std::cout << "all complete" << std::endl;
});
}
mutable std::mutex _mutex;
};
int main() {
std::condition_variable controller_done;
std::mutex done_mutex;
bool is_controller_done = 0;
// make shared controller and start its processing
auto pcontroller = std::shared_ptr<Controller>{ new Controller,
[&](auto*p) {
delete p;
auto lock = std::unique_lock<std::mutex>(done_mutex);
is_controller_done = true;
std::cout << "controller destroyed" << std::endl;
lock.unlock();
controller_done.notify_all();
}};
Controller::start(pcontroller);
// destroy the controlling pointer. but our controller is still running...
pcontroller.reset();
auto lock = std::unique_lock<std::mutex>(done_mutex);
controller_done.wait(lock, [&]{ return is_controller_done;});
std::cout << "program ends" << std::endl;
}
Code: http://coliru.stacked-crooked.com/a/281b0ef6d1b31c56

Something about shared_ptr I don't get

When I run this code:
#include <iostream>
#include <memory>
struct Adaptee {
int value = 0;
};
class Adapter {
private:
Adaptee* adaptee;
public:
Adapter (Adaptee* a) : adaptee(a) {}
void increaseValueByOne() {adaptee->value++;}
};
int main() {
Adaptee* a = new Adaptee;
Adapter* adapter = new Adapter(a);
adapter->increaseValueByOne();
delete adapter;
std::cout << "a->value = " << a->value << std::endl;
}
I get the output: a->value = 1. But when I run this:
struct Adaptee {
int value = 0;
};
class Adapter {
private:
std::shared_ptr<Adaptee> adaptee;
public:
Adapter (Adaptee* a) : adaptee (std::shared_ptr<Adaptee>(a)) {}
void increaseValueByOne() {adaptee->value++;}
};
int main() {
Adaptee* a = new Adaptee;
Adapter* adapter = new Adapter(a);
adapter->increaseValueByOne();
delete adapter;
std::cout << "a->value = " << a->value << std::endl;
}
I get: a->value = 7738248
Why is this? Isn't the use_count of adapter->adaptee simply changing from 2 to 1, so nothing should go wrong? When I remove the line 'delete adapter;' everything is fine though, but then there is leaking.
Because in the second case Adaptee instance is deleted by the destructor of shared_ptr when you delete adapter as it's the last shared_ptr owning that object. See the doc.
If you want to keep the adaptee alive after you delete adapter, you should wrap it into shared_ptr from the start:
class Adapter {
private:
std::shared_ptr<Adaptee> adaptee;
public:
Adapter (const std::shared_ptr<Adaptee>& a) : adaptee (a) {}
void increaseValueByOne() {adaptee->value++;}
};
int main() {
std::shared_ptr<Adaptee> a(new Adaptee);
Adapter* adapter = new Adapter(a);
adapter->increaseValueByOne();
delete adapter;
std::cout << "a->value = " << a->value << std::endl;
}
In the first case, the line
delete adapter;
did nothing to adaptee. It is still a valid pointer.
In the second case, the same line calls the destructor of the shared_ptr, which deallocates the memory pointed to by adaptee. Hence, adaptee is not a valid pointer and you can expect undefined behavior if you dereference it.
The principle of the shared_ptr is to manage the deletion of the pointed object when it's no longer used.
When you create the shared_ptrin your adapter, it takes ownership of the object and sets the use count to 1. When the adapter is deleted, so is the shared pointer. THe use count (that you can display with use_count()) is hence automatically decremented and reaches zero. So the object is deleted and a points to an invalid address.
If you dont' want the shared_ptr to release the memory of a when deleting adapter, you should create your original pointer as shared_pointer as well:
int main() {
auto a = std::make_shared<Adaptee>(); //shared pointer instead of Adaptee* a = new Adaptee;
...
}
And add an additional constructor in class Adapter:
Adapter(std::shared_ptr<Adaptee> a) : adaptee(a) {}
With this consistent use of shared_ptr,the use count of shared pointer would go to 1 when adapter is deleted, and the rest of your code will work as you exepect, printing 1 as in your original version.
To expand on what others are saying, when you give a raw heap allocated pointer to a shared_ptr, you are giving the shared_ptr control over the lifetime of the resource. shared_ptr keeps a reference count of how many shared_ptrs are pointing to a resource. When that count is 0 the resource is cleaned up.
adaptee (std::shared_ptr<Adaptee>(a))
Here, the reference count is 1 because there is 1 shared_ptr pointing to the resource a.
delete adapter;
causes the shared_ptr in adapter to go out of scope. The shared_ptr's destructor is called, which decrements the reference count. Since the reference count is now 0, delete is called on a.
std::cout << "a->value = " << a->value << std::endl;
Here, a is no longer a valid pointer because delete was called in the destructor of the shared_ptr.
If you want a to stay valid you should do the following:
struct Adaptee {
int value = 0;
};
class Adapter {
private:
std::shared_ptr<Adaptee> adaptee;
public:
Adapter (std::shared_ptr<Adaptee> a) : adaptee(a) {}
void increaseValueByOne() {adaptee->value++;}
};
int main() {
std::shared_prt<Adaptee> a = std::make_shared<Adaptee>(); //reference count is 1
Adapter* adapter = new Adapter(a); //reference count is 2
adapter->increaseValueByOne();
delete adapter; //reference count is 1
std::cout << "a->value = " << a->value << std::endl;
} // reference count is 0; memory is deallocated

Automatically adding and removing an object from a list

I have a class. When this class is instantiated, I want the instance added to a list. When the object is deleted, I want it removed from the list.
So I give the object a shared pointer to itself. I then have a list of weak pointers to those shared pointers. When an object is created, it creates a shared pointer to itself, makes a weak pointer to that, and puts the weak pointer in a list.
When the object is destroyed, the shared pointer is as well. Whenever I try to access a member in the list, I ensure that it hasn't expired and that its use count isn't 0. Despite this, I still crash when the list member is destroyed. Why? Can I get around it? Here's my SSCCE:
#include <iostream>
#include <memory>
#include <vector>
class test
{
private:
std::shared_ptr<test> self;
public:
int val;
test(int set);
test(test &copy) = delete; // making sure there weren't issues
// with a wrong instance being deleted
};
std::vector<std::weak_ptr<test>> tests;
test::test(int set):
val(set)
{
this->self = std::shared_ptr<test>(this);
tests.push_back(std::weak_ptr<test>(this->self));
}
void printTests()
{
for (auto i = tests.begin(); i != tests.end(); i++)
{
if (i->use_count() == 0 || i->expired())
{
tests.erase(i);
continue;
}
std::cout << i->lock()->val << std::endl;
}
std::cout << std::endl;
}
int main(int argc, char **argv)
{
{
test t(3);
std::cout << "First tests printing: " << std::endl;
printTests();
} // SEGFAULTS HERE
std::cout << "Second tests printing: " << std::endl;
printTests();
return 0;
}
The output of this program is as follows:
First tests printing:
3
Segmentation fault (core dumped)
Your issue is with how you are creating the self pointer:
this->self = std::shared_ptr<test>(this);
When a shared_ptr is created with this constructor, according to the documentation,
When T is not an array type, constructs a shared_ptr that owns the pointer p.
...
p must be a pointer to an object that was allocated via a C++ new expression or be 0
So the issue is that the shared_ptr is taking ownership of your stack object, so when the object gets destructed (and the shared_ptr along with it), shared_ptr is trying to delete your object that is on the stack. This is not valid.
For your use case, if you expect tests to outlive your vector, then you might be able to just store this.
I think the OP is interested in a solution to his original problem even if it uses a different method than the one he attempted. Here is a simple example of how to add an object to a global list when it is constructed, and remove it when it is deleted. One thing to remember: you must call AddList in every constructor you add to your base class. I didn't know whether you want the list to be accessible outside the class or not, so I added getter functions to return non-const iterators to the list.
class MyClass
{
private:
static std::list<MyClass*> mylist;
std::list<MyClass*>::iterator mylink;
// disable copy constructor and assignment operator
MyClass(const MyClass& other);
MyClass& operator = (const MyClass& other);
void AddList()
{
mylink = mylist.insert(mylist.end(), this);
}
void RemoveList()
{
mylist.erase(mylink);
}
public:
MyClass()
{
AddList();
}
virtual ~MyClass()
{
RemoveList();
}
static std::list<MyClass*>::iterator GetAllObjects_Begin()
{
return mylist.begin();
}
static std::list<MyClass*>::iterator GetAllObjects_End()
{
return mylist.end();
}
virtual std::string ToString() const
{
return "MyClass";
}
};
class Derived : public MyClass
{
virtual std::string ToString() const
{
return "Derived";
}
};
std::list<MyClass*> MyClass::mylist;
int main()
{
std::vector<MyClass*> objects;
objects.push_back(new MyClass);
objects.push_back(new MyClass);
objects.push_back(new Derived);
objects.push_back(new MyClass);
for (std::list<MyClass*>::const_iterator it = MyClass::GetAllObjects_Begin(), end_it = MyClass::GetAllObjects_End(); it != end_it; ++it)
{
const MyClass& obj = **it;
std::cout << obj.ToString() << "\n";
}
while (! objects.empty())
{
delete objects.back();
objects.pop_back();
}
}
This line is trouble:
tests.erase(i);
An iterator pointing to the erased element is invalid, and you can't increment it any longer. Luckily, erase returns a new iterator you can use:
auto i = tests.begin();
while (i != tests.end())
{
if (i->use_count() == 0 || i->expired())
{
i = tests.erase(i);
}
else {
std::cout << i->lock()->val << std::endl;
++i;
}
}