I use shared_ptr to handle pointers like this in my program.
struct D
{
D() { std::cout << "D ctor\n"; }
~D() { std::cout << "D dtor\n"; }
};
struct CC
{
private:
std::vector<std::shared_ptr<D>> pDs;
static std::shared_ptr<CC> pC;
CC() { std::cout << "C ctor\n"; };
public:
static std::shared_ptr<CC> GetInstance()
{
if (nullptr == pC)
{
pC = std::shared_ptr<CC>(new CC);
return pC;
}
return pC;
}
void Save(std::shared_ptr<D> d)
{
pDs.emplace_back(d);
std::cout << "saved b\n";
}
void Delete(int i)
{
pDs.erase(pDs.begin() + i);
}
int Size() { return pDs.size(); }
~CC() { std::cout << "C dtor\n"; }
};
std::shared_ptr<CC> CC::pC(nullptr);
struct Caller
{
void Init()
{
std::shared_ptr<D> d = std::shared_ptr<D>(new D());
CC::GetInstance()->Save(d);
}
int Size()
{
return CC::GetInstance()->Size();
}
};
struct Deletor
{
void Delete(int i)
{
CC::GetInstance()->Delete(i);
}
};
Using this in a console application, there is no error.
My question is,
if I save or clone many instances of shared_ptr in 2 or more different map/vector objects (shared_ptr are used as their values) as shown above, and at some point I would want to remove 1 or more instances of them (via e.g erase(key/iterator)) of one object, how can I manipulate their twins that are stored in other objects?
For example,
MAP_A = MAP_B = {key,shared_ptr}
MAP_A.erase(key_i);
//what should I do with MAP_B(key_i)?
how can I manipulate their twins that are stored in other objects?
No need. That's the entire point for having a shared_ptr.
As per std::shared_ptr:
std::shared_ptr is a smart pointer that retains shared ownership
of an object through a pointer. Several shared_ptr objects may own
the same object.
It has a reference counting mechanism that tracks how many pointers are sharing the "shared" object.
leaks in destructors
Once reference count is zero that's the time the shared object is freed.
This guarantees that there will be at most no leaks.
Related
Why does the following code print 0, but if you comment out "std::string my_string" it prints 1?
#include <stdio.h>
#include <iostream>
class A {
public:
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
class B : public A {
public:
int foo() {
return 1;
}
};
int main()
{
A* a;
if (true) {
B b;
a = &b;
}
std::cout << a->foo() << std::endl;
return 0;
}
I also understand that changing std::string to std:string* also causes the code to print 1, as does removing the if-statement, though I don't understand why any of that is true.
EDIT: This seems to be due to a dangling pointer. Then what's the standard pattern in C++ to do something like this in Java:
Animal animal;
boolean isDog = false;
// get user input to set isDog
if (isDog) {
animal = new Dog();
} else {
animal = new Cat();
}
animal.makeNoise(); // Should make a Dog/Cat noise depending on value of isDog.
Problem
The program has Undefined Behaviour. b is only in scope inside the body of the if. You can't count on logical results when accessing a dangling pointer.
int main()
{
A* a;
if (true) {
B b; // b is scoped by the body of the if.
a = &b;
} // b's dead, Jim.
std::cout << a->foo() << std::endl; // a points to the dead b, an invalid object
return 0;
}
TL;DR Solution
int main()
{
std::unique_ptr<A> a; // All hail the smart pointer overlords!
if (true) {
a = std::make_unique<B>();
}
std::cout << a->foo() << std::endl;
return 0;
} // a is destroyed here and takes the B with it.
Explanation
You can point a at an object with a dynamic lifetime
int main()
{
A* a;
if (true) {
a = new B; // dynamic allocation
} // b's dead, Jim.
std::cout << a->foo() << std::endl;
delete a; // DaANGER! DANGER!
return 0;
}
Unfortunately delete a; is also undefined behaviour because A has a non-virtual destructor. Without a virtual destructor the object pointed at by a will be destroyed as an A, not as a B.
The fix for that is to give A a virtual destructor to allow it to destroy the correct instance.
class A {
public:
virtual ~A() = default;
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
There is no need to modify B because once a function is declared virtual, it stays virtual for its children. Keep an eye out for final.
But it's best to avoid raw dynamic allocations, so there is one more improvement we can make: Use Smart pointers.
And that brings us back to the solution.
Documentation for std::unique_ptr
Documentation for std::make_unique
I need to design a struct data which will hold pointer to Base data type. User should be able to easily create object of this data struct and pass around without handling much of memory management issues.
I have created few structures, please suggest the correct way to handle it.
struct BaseData {
enum DataType { DATATYPE_1, DATATYPE_2 };
virtual ~BaseData() { cout << "BaseData Dtor" << endl; }
};
struct DataType1 : BaseData {
virtual ~DataType1() { cout << "DataType1 Dtor" << endl; }
};
struct DataType2 : BaseData {
virtual ~DataType2() { cout << "DataType2 Dtor" << endl; }
};
struct Data {
Data() { cout << "Data Ctor" << endl; }
Data(const Data& o) {
if (o.baseData->type == BaseData::DATATYPE_1) {
baseData = new DataType1;
*(static_cast<DataType1*>(baseData)) = *(static_cast<DataType1*>(o.baseData));
}
else if (o.baseData->type == BaseData::DATATYPE_2) {
baseData = new DataType2;
*(static_cast<DataType2*>(baseData)) = *(static_cast<DataType2*>(o.baseData));
}
}
virtual ~Data() {
cout << "Data Dtor" << endl;
delete baseData; //here it results in segmentation fault if object is created on stack.
baseData = NULL;
}
BaseData* baseData;
};
vector <Data> vData;
void addData(const Data& d) { cout << "addData" << endl; vData.push_back(d); }
The client code looks like below.
int main()
{
{
DataType1 d1;
d1.type = BaseData::DATATYPE_1;
Data data;
data.baseData = &d1;
addData(data);
}
{
BaseData* d2 = new DataType2;
d2->type = BaseData::DATATYPE_2;
Data data;
data.baseData = d2;
addData(data);
delete d2;
d2 = NULL;
}
{
Data data;
data.baseData = new DataType1;
static_cast<DataType1*>(data.baseData)->type = BaseData::DATATYPE_1;
addData(data);
delete data.baseData;
data.baseData = NULL;
}
}
Code in block 1 and block 2 crashes due to double deletion. How can i handle all these use cases properly.
One way what I have thought of is, hide baseData pointer using private and provide a method to user setBaseData(const BaseData& o) in struct Data.
void setBaseData(const BaseData& o) {
cout << "setBaseData" << endl;
if (o.type == BaseData::DATATYPE_1) {
baseData = new DataType1;
*(static_cast<DataType1*>(baseData)) = static_cast<const DataType1&>(o);
}
else if (o.type == BaseData::DATATYPE_2) {
baseData = new DataType2;
*(static_cast<DataType2*>(baseData)) = static_cast<const DataType2&>(o);
}
}
With setBaseData() I am able to avoid segmentation fault and user is free to create object of struct Data in which ever he likes.
Is there any better way to design these classes?
Your problem is that you are trying to manage ownership by yourself. Instead you could use explicit ownership management using the unique_ptr type.
Assuming the same type definitions you used (+ The createDataType method we'll see later):
struct BaseData {
enum DataType { DATATYPE_1, DATATYPE_2 };
virtual ~BaseData() { cout << "BaseData" << endl; }
static std::unique_ptr<BaseData> createDataType(DataType type);
};
struct DataType1 : BaseData {
virtual ~DataType1() { cout << "DataType1" << endl; }
};
struct DataType2 : BaseData {
virtual ~DataType2() { cout << "DataType2" << endl; }
};
Notice that we are now using a factory for creating our objects, like so:
static std::unique_ptr<BaseData> BaseData::createDataType(BaseData::DataType type) {
switch(type) {
case BaseData::DATATYPE_1:
return std::make_unique<DataType1>();
case BaseData::DATATYPE_2:
return std::make_unique<DataType2>();
default:
throw std::runtime_error("ERR");
}
}
Then, you should declare your managing Data object as follows:
struct Data {
Data()
: baseData(nullptr) {}
Data(std::unique_ptr<BaseData> data)
: baseData(std::move(data)) {}
Data(Data && rhs)
: baseData(std::move(rhs.baseData)) {}
std::unique_ptr<BaseData> baseData;
};
And now we could write clean, clear and safe code as this:
vector<Data> vData;
void addData(Data&& d) {
if (dynamic_cast<DataType1 *>(d.baseData.get()) != nullptr)
cout << "Adding DataType 1" << endl;
else if (dynamic_cast<DataType2 *>(d.baseData.get()) != nullptr)
cout << "Adding DataType 2" << endl;
vData.push_back(std::move(d));
}
int main()
{
{ // Option 1: Create base data somewhere, create data from it
auto baseData = createDataType(BaseData::DATATYPE_1);
Data data { std::move(baseData) };
addData(std::move(data));
}
{ // Option 2: Create data directly knowing the base data type
Data data { createDataType(BaseData::DATATYPE_2) };
addData(std::move(data));
}
{ // Option 3: Create data and add it to the vector
addData({ createDataType(BaseData::DATATYPE_1) });
}
}
And you could always check for the actual type of the baseData using the same dynamic casts as in addData
Code in block 1 and block 2 crashes due to double deletion. How can i handle all these use cases properly.
By following the rule of 3 (or rule of 5 if you would like to support efficient move operations):
if a class defines one (or more) of the following it should probably explicitly define all three:
destructor
copy constructor
copy assignment operator
You've neglected implementing a custom copy assignment operator. The use of the default copy assignment operator results in the double deletion.
Also, never assign a pointer to an automatic variable to Data::baseData like you do here in block 1.
The destructor of Data will delete this pointer, which results in undefined behaviour.
Also, never delete the pointer owned by Data::baseData unless you're going to replace it with something else.
To avoid doing these by accident, I recommend declaring Data::baseData private as you've already considered.
Is there any better way to design these classes?
Yes. Don't ever use bare pointers to owned memory. Use std::unique_ptr instead.
Usually I prefer returning unique_ptr from Factories.
Recently I came to the problem of returning a unique_ptr for a class that inherits enable_shared_from_this. Users of this class may accidentally cause a call to shared_from_this(), though it is not owned by any shared_ptr, which results with a std::bad_weak_ptr exception (or undefined behavior until C++17, which is usually implemented as an exception).
A simple version of the code:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
shared_ptr<Foo> get_shared() {return shared_from_this();}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = pb2->get_shared();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
pb5->doIt();
}
A possible solution is to change the factory method to return shared_ptr but this is not what I'm looking for, as in many cases there is actually no need for sharing and this will make things less efficient.
The question is how to achieve all of the following:
allow the factory to return unique_ptr
allow unique_ptr of this class to become shared
allow shared_ptr of this class to get shared copies (via shared_from_this())
avoid failure when unique_ptr of this class tries to get shared from this (calling get_shared in above example)
Items 1 to 3 are fulfilled with the code above, the problem is with item 4.
The problem with the member function get_shared in the question is that it allows calls by both unique_ptr and shared_ptr with a difficult to distinguish between the two, thus unique_ptr is allowed to call this method and fails.
Moving the get_shared to be a static method which gets the pointer to share from, allows the distinguishing between unique and share which fixes this problem:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
static shared_ptr<Foo> get_shared(unique_ptr<Foo>&& unique_p) {
return shared_ptr<Foo>(std::move(unique_p));
}
static shared_ptr<Foo> get_shared(const shared_ptr<Foo>& shared_p) {
return shared_p->shared_from_this();
}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior - almost as before
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// ok behavior!
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = Foo::get_shared(std::move(pb4));
pb5->doIt();
}
Code: http://coliru.stacked-crooked.com/a/7fd0d462ed486c44
Deriving from enable_shared_from_this is a promise that your instances are owned by a (group of) shared_ptr. Don't lie about this, only ever create shared_ptr<Foo> and never hand out unique_ptr<Foo>.
It's not worth the future pain when you have to disentangle the "safe" uses of unique_ptr<Foo> from the case where a Foo & deep in some logic that wants to call shared_from_this but sometimes is actually a unique_ptr<Foo>.
Use multiple static factory functions and conversion functions. To address your comments, I've added get_shared to support copying a shared pointer. This compiles and is available here: http://ideone.com/UqIi3k
#include <iostream>
#include <memory>
class Foo
{
std::string name;
Foo(const std::string& _name) : name(_name) {}
public:
void doIt() const { std::cout << "Foo::doIt() <" << name << '>' << std::endl;}
virtual ~Foo() { std::cout << "~Foo() <" << name << '>' << std::endl;}
static std::unique_ptr<Foo> create_unique(const std::string & _name) {
return std::unique_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> create_shared(const std::string & _name) {
return std::shared_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> to_shared(std::unique_ptr<Foo> &&ptr ) {
return std::shared_ptr<Foo>(std::move(ptr));
}
static std::shared_ptr<Foo> get_shared(const std::shared_ptr<Foo> &ptr) {
return std::shared_ptr<Foo>(std::move(ptr));
}
};
int main() {
// ok behavior
auto pb1 = Foo::create_unique("pb1");
pb1->doIt();
std::shared_ptr<Foo> pb2 = Foo::get_shared(std::move(pb1));
//note the change below
std::shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// also OK behavior
auto pb4 = Foo::create_unique("pb4");
pb4->doIt();
std::shared_ptr<Foo> pb5 = Foo::to_shared(std::move(pb4)); // no exception now
pb5->doIt();
std::shared_ptr<Foo> pb6 = Foo::create_shared("pb6");
pb6->doIt();
std::shared_ptr<Foo> pb7 = std::shared_ptr<Foo>(pb5);
pb7->doIt();
return 0;
}
That's exactly what I was looking for, making sure that clients may reach a point that sharing is required and it will work transparently without really caring if they are with a shared Pet or with a unique Pet (i.e. making the interface easy to use correctly etc.).
It sounds like the x-y problem to me.
To "make sure that clients can share if required", turn this into a separate tool and put this in your toolset (edit: but it still feels like you have the x-y problem):
namespace tools
{
/// #brief hides the details of sharing a unique pointer
/// behind a controlled point of access
///
/// to make sure that clients can share if required, use this as a
/// return type
template<typename T>
class pointer final
{
public:
// #note: implicit on purpose (to enable construction on return,
// in the client code below)
pointer(std::unique_ptr<T> value);
// #note: implicit on purpose (to enable construction on return,
// in the client code below)
pointer(std::shared_ptr<T> value);
T* const operator->() const { return get(); }
/// #note copy&swap
pointer& operator=(pointer p)
{
using std::swap;
swap(value1, p.value1);
swap(value2, p.value2);
return *this;
}
// example copy
pointer(const pointer<T>& value)
: value1{}, value2{ value.share() }
{
}
// example move
pointer(pointer<T>&& tmp)
: value1{ std::move(tmp.value1) }, value2{ std::move(tmp.value2) }
{
}
/// #note conceptually const, because it doesn't change the address
/// it points to
///
/// #post internal implementation is shared
std::shared_ptr<T> share() const
{
if(value2.get())
return value2;
value2.reset(value1.release());
return value2;
}
T* const get() const
{
if(auto p = value1.get())
return p;
return value2;
}
private:
mutable std::unique_ptr<T> value1;
mutable std::shared_ptr<T> value2;
};
}
Your client code then becomes:
class Foo
{
string name;
Foo(const string& _name) : name(_name) {}
public:
using pointer = tools::pointer<Foo>;
static pointer make_unique(const string& name)
{
return std::make_unique<Foo>(name);
}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::make_unique("pb1");
pb1->doIt(); // call through unique pointer
auto pb2 = pb1.share(); // get copy of shared pointer
auto pb3 = pb1; // get copy of shared pointer
auto pb4 = std::move(pb1); // move shared pointer
}
As you will have found, once an object is managed by a shared_ptr, there is no (safe) way to unshare it. This is by design, since once the lifetime of the object is shared, no one owner can guarantee that it will ever be the sole owner again (except during the execution of the deleter - I'll leave you to reason about whether that's useful to you).
However, the standard library does allow you to specialise any std class template provided it's specialised for a user defined class.
So what you can do is this:
namespace std {
template<class Deleter>
struct unique_ptr<Foo, Deleter> {
static_assert(!std::is_same<Deleter, Deleter>::value, "sorry, not allowed");
// or
static_assert(!sizeof(Deleter), "sorry, not allowed");
// (thanks to Jarod42 && md5i for cleaning up after me)
};
}
And now no unique_ptr can ever own your object (which is clearly designed to be owned only by a shared_ptr).
This is enforced at compile time.
An old thread already, but I stumbled to ponder a question if its always quaranteed that weak_from_this().expired()==true or weak_from_this().use_count() == 0 for an object not managed by shared_ptr - including unique_ptr. If yes, then simple answer to original question could be to realize non-throwing version of shared_from_this() via such checks for objects returned from factory.
May be we can template check of the calling variable ::
class Foo : public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
template <typename T>
shared_ptr<Foo> get_shared() { return shared_ptr<Foo>(); }
template <>
shared_ptr<Foo> get_shared<unique_ptr<Foo>>() { return shared_ptr<Foo>(); }
template <>
shared_ptr<Foo> get_shared<shared_ptr<Foo>>() { return shared_from_this(); }
void doIt()const { cout << "Foo::doIt() <" << name << '>' << endl; }
virtual ~Foo() { cout << "~Foo() <" << name << '>' << endl; }
};
int main()
{
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2{ std::move(pb1) };
shared_ptr<Foo> pb3 = pb2->get_shared<decltype(pb2)>();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared<decltype(pb4)>(); // exception
if (pb5 != nullptr)
pb5->doIt();
return 0;
}
I am not sure if that is exactly what you want, but might solve the point 4 you have mentioned.
I created some code to reproduce the problem:
#include "stdafx.h"
#include <iostream>
#include <vector>
class A
{
protected:
int m_X;
public:
A() {
std::cout << "in A ctor" << std::endl;
m_X = 0;
}
virtual void printX(){ std::cout << "in A " << m_X << std::endl; }
};
class B : public A
{
public:
B() {
std::cout << "in B ctor" << std::endl;
m_X = 1;
}
virtual void printX(){ std::cout << "in B " << m_X << std::endl; }
};
class As
{
public:
void AddA( const A &a ){ m_As.push_back( a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a.printX();
}
}
private:
std::vector<A> m_As;
};
int _tmain(int argc, _TCHAR* argv[])
{
As as;
B b;
as.AddA( b );
as.PrintXs();
system("pause");
return 0;
}
The output of this is:
in A ctor
in B ctor
in A 1
I want "in B 1" instead of "in A 1". I'm sure my understanding of virtual is flawed. How must I change the code to call the B PrintX()? Note that there will be other classes that inherit from A so I really don't want to code a static call.
Thanks.
What you're doing is called slicing. This is where you take an object of a derived class and trim off everything that is not in the parent and assign it to the parent.
What you want to do is use polymorphism to do what you explained. To do this, change your vector from a copy of the object, to a ptr to the object.
If interested in more details, please use the links provided, the information included in them seems to be very complete.
The quick fix is to change your As class to the following:
class As
{
public:
void AddA( A &a ){ m_As.push_back( &a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a->printX();
}
}
private:
std::vector<A*> m_As;
};
When you use std::vector<A> m_As;, the vector can only fit A objects. If you use pointers instead then polymorphism can work and call the correct printX function. However, this has the problem of dangling pointer if the lifetime of the pointed to object expires. To handle that it would be better to use a smart pointer class like std::unique_ptr.
Since you're passing objects by value you can not take advantages of polymorphism. Pass them by (smart) pointers or references.
std::vector<std::shared_ptr<A>> m_As;
// or
std::vector<std::unique_ptr<A>> m_As;
// or
std::vector<A*> m_As; // be careful of bare pointers
// or (since C++11)
std::vector<std::reference_wrapper<A>> m_As;
std::reference_wrapper magic!
For the last one, you can use std::reference_wrapper and std::ref:
class As
{
public:
void AddA(A &a){ m_As.push_back( std::ref(a) ); }
void PrintXs() const
{
for ( auto a : m_As )
{
a.get().printX();
}
}
private:
std::vector<std::reference_wrapper<A>> m_As;
};
Using last code, you don't have to change main code.
Live code
for ( const auto & a : m_As )
{
a.printX();
}
it will keep you from expanded copy and provide the B-instance instead of A-instance, appeared as copy.
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 ©) = 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;
}
}