I have a singleton with attributes which are pointers.
How do I prevent a memory leak when I no longer use it i.e. when the last reference to my instance is popped off the stack frame?
Does the destructor get called each time a reference gets poped off the stack?
A &A::getInstance()
{
static A instance; // does this get deleted at any point?
return instance;
}
Your singleton object will exist for the lifetime of the program and will be destroyed some time after main ends. At that point it's destructor will be invoked.
Here you may delete your raw pointers (or if using smart, you can set to nullptr or call reset).
This can be seen in action with the example below:
#include <iostream>
#include <string>
#include <memory>
class Foo
{
public:
Foo(std::string const& name = "Unknown")
: m_sName{ name }
{
std::cout << m_sName << " is created" << std::endl;
}
~Foo()
{
std::cout << m_sName << " is being destroyed" << std::endl;
}
std::string m_sName;
};
class Singleton
{
public:
static Singleton& Get()
{
static Singleton instance;
return instance;
}
~Singleton()
{
delete m_RawFoo;
m_SmartFoo = nullptr;
}
void print() const
{
std::cout << "Hello World" << std::endl;
}
protected:
private:
Singleton()
{
m_RawFoo = new Foo{ "Raw Foo" };
m_SmartFoo = std::make_shared<Foo>("Shared Foo");
}
Foo* m_RawFoo;
std::shared_ptr<Foo> m_SmartFoo;
};
int main()
{
std::cout << "Starting main..." << std::endl;
Singleton::Get().print();
Singleton::Get().print();
std::cout << "Ending main..." << std::endl;
return 0;
}
Which outputs the following:
Starting main...
Raw Foo is created
Shared Foo is created
Hello World
Hello World
Ending main...
Raw Foo is being destroyed
Shared Foo is being destroyed
I usually use shared_ptr and weak_ptr for singletons. The following is a singleton which is alive only while there are references to it. Note that this is not entirely thread-safe. If you want thread-safety, you'll need some additional logic (probably a lock) in GetInstance.
#include <memory>
class MySingleton
{
// singleton
public:
static std::shared_ptr<MySingleton> GetInstance();
private:
static std::weak_ptr<MySingleton> instance__;
// lifecycle
private:
MySingleton();
public:
~MySingleton();
// delete the copy constructor, move constructor, copy operator and move operator
private:
MySingleton(const MySingleton&) = delete;
MySingleton(MySingleton&&) = delete;
MySingleton& operator=(const MySingleton&) = delete;
MySingleton& operator=(MySingleton&&) = delete;
};
std::shared_ptr<MySingleton> MySingleton::GetInstance()
{
auto instance = instance__.lock();
if (!instance) {
instance.reset(new MySingleton);
instance__ = instance;
}
return instance;
}
std::weak_ptr<MySingleton> MySingleton::instance__;
MySingleton::MySingleton()
{
// initialization logic here
}
MySingleton::~MySingleton()
{
// clean-up logic here
}
Here's some sample client code:
int main()
{
// proper usage -- store the reference in a stack variable for the duration of its use
{
auto instance = MySingleton::GetInstance();
instance->doSomething();
instance->doSomethingElse();
// instance shared_ptr will be destructed automatically,
// which will then destruct the MySingleton instance
}
// BAD USAGE -- failing to store the reference will cause a new instance to be created and destroyed with each call
{
MySingleton::GetInstance()->doSomething();
MySingleton::GetInstance()->doSomethingElse();
}
// proper usage -- store the reference in a struct or class whose lifecycle is managed appropriately
{
// this class takes a shared reference and stores it
class Foo
{
public:
Foo(const std::shared_ptr<MySingleton>& dependency) : dependency_(dependency) { }
private:
std::shared_ptr<MySingleton> dependency_;
};
// this instance will store a shared reference
auto f = new Foo(MySingleton::GetInstance());
// when the destructor is invoked, the shared_ptr will be destructed,
// which will then destruct the MySingleton instance
delete f;
}
return 0;
}
Related
I got a class which holds the application's logger as a unique_ptr. The logger can be set through a static function. Also, one can obviously log messages. I left out any thread synchronization (mutexes) to make things easier.
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<logger::ILogger> new_logger);
static void Log(const std::string& message);
private:
static std::unique_ptr<logger::ILogger> logger_;
};
void LoggerWrapper::Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
}
void LoggerWrapper::SetLogger(std::unique_ptr<logger::ILogger> new_logger) {
logger_ = std::move(new_logger);
}
My problem is: The unique_ptr gets destructed before some of the other classes inside the application. E.g. is the DTOR of Class Foo wants to log something, the unique_ptr might have already been destroyed (which is the case at the moment). This causes the ILogger implementation to be destroyed, resulting in no log output being possible.
Does anyone have an idea on how to easily fix this? I somehow need to "delay" the destruction of the static unique_ptr. I also tried changing it to a shared_ptr, but that only caused SIGABRTs with "pure virtual method called" errors.
Thanks in advance!
EDIT: Created a minimal working example which contradicts my experience. In this case, the static logger outlives the Foo class.
EDIT2: My application uses exit. That seems to change the order of destruction.
EDIT3: exit does not destroy local objects.
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
logger_ = std::move(new_logger);
}
static void Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
private:
static std::unique_ptr<ILogger> logger_;
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
// declaring logger_ first causes it to be deleted AFTER foo
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
foo = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
This is trivial.
First you don't use global static objects ( you should not be using global state like that). You use function static objects so you can control the order of creation/destruction.
So change this:
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
Into:
class GlobalLogger
{
public:
ILogger& getLogger() {
static ILogger logger; // if you must use unique_ptr you can do that here
return logger; // But much simpler to use a normal object.
}
};
class GlobalFoo
{
public:
Foo& getFoo() {
// If there is a chance that foo is going to
// use global logger in its destructor
// then it should simply call `GlobalLogger::getLogger()`
// in the constructor of Foo. You then
// guarantee the order of creation and thus destruction.
// Alternatively, you can call it here in thus
// function just before the declaration of foo.
static Foo foo;
return foo;
}
};
// Where you were using `logger_` use `GlobalLogger::getLogger()`
// Where you were using `foo` use `GlobalFoo::getFoo()`
If we use your original code as the starting point we can do this:
#include <iostream>
#include <memory>
#include <string>
// Please don't do this.
// This is the number one worst practice.
// https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper
{
// Here store the logger
// as a static member of this private function.
// The the SetLogger() Log() functions get this reference.
static std::unique_ptr<ILogger>& getLogReference() {
static std::unique_ptr<ILogger> logger;
return logger;
}
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
// Save the new reference.
getLogReference() = std::move(new_logger);
}
// Use the logger if it has been set.
static void Log(const std::string& message) {
std::unique_ptr<ILogger>& logger_ = getLogReference();
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
// This calls Log()
// Which calls getLogReference()
// Which forces the creation of the function static
// variable logger so it is created before this
// object is fully initialized (if it has not already
// been created).
//
// This means this object was created after the logger
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
// Because the Log() function was called in the
// constructor we know the loger was fully constructed first
// thus this object will be destroyed first
// so the logger object is guaranteed to be
// available in this objects destructor
// so it is safe to use.
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
std::unique_ptr<Foo>& globalFoo() {
// foo may destroy an object created later
// that has a destructor that calls LoggerWrapper::Log()
// So we need to call the Log function here before foo
// is created.
LoggerWrapper::Log("Initializing Global foo");
// Note: Unless somebody else has explicitly called SetLogger()
// the above line is unlikely to log anything as the logger
// will be null at this point.
static std::unique_ptr<Foo> foo;
return foo;
}
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
globalFoo() = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
The order in which static (global) objects are created and destroyed is undefined. This leave you a few options.
Don't use global objects, just raw use pointers which you can destroy yourself in the correct order.
Use a pointer to your logger that you never destroy. This technically is a memory leak but the kernel will cleanup when your application exits.
Use a shared_ptr for your logger. Each object that uses the logger gets a shared_ptr and the logger will be cleaned up after the last object is destroyed.
I designed an App that holds a stack of layers and an active obj.
When a Layer is attached to the App, the Layer tells App what an active object is. But my design causes a sigtrap when deallocating.
It cause sigtrap because the destruction of shared_ptr<Obj> m_obj in App happens first which reduce the use_count to 1. Then the onDetech function gets call, setting the active shared_ptr<Obj> m_obj to nullptr and reduce use_count to 0! But the layer still holds an shared_ptr<Obj>.
The code below is a minimal example to reproduce. I notice my code has a reference cycle but I have no idea how to fix this except using a raw pointer for obj in the App class.
I used shared_ptr for obj in App because it makes sense to me that App has the shared ownership of obj. Should I not use shared_ptr in this case?
class App;
class Obj {
public:
~Obj() { std::cout << "obj destruct" << std::endl; }
};
class Layer {
public:
Layer() { m_obj = std::make_shared<Obj>(); }
~Layer() { std::cout << m_obj.use_count() << std::endl; }
void onAttach(App *app);
void onDetach();
std::shared_ptr<Obj> m_obj;
private:
App *m_app;
};
class LayerStack {
public:
void pushLayer(App *app, std::shared_ptr<Layer> layer) {
m_layers.push_back(layer);
layer->onAttach(app);
}
~LayerStack() {
for (auto &layer : m_layers) {
layer->onDetach();
}
}
private:
std::vector<std::shared_ptr<Layer>> m_layers;
};
class App {
public:
App() {
m_defaultLayer = std::make_shared<Layer>();
m_stack.pushLayer(this, m_defaultLayer);
}
~App() {}
LayerStack m_stack;
std::shared_ptr<Layer> m_defaultLayer;
std::shared_ptr<Obj> m_activeObj;
};
void Layer::onAttach(App *app) {
m_app = app;
app->m_activeObj = m_obj;
std::cout << m_obj.use_count() << std::endl;
}
void Layer::onDetach() {
m_app->m_activeObj = nullptr;
std::cout << m_obj.use_count() << std::endl;
}
int main() {
A a;
}
output:
2
obj destruct
-923414512
-923414512
You're accessing m_activeObj after its lifetime has ended, and thus the behavior of your program is undefined.
The sequence of events is as follows:
App object goes out of scope
~App runs
m_activeObj is destroyed; after this its lifetime has ended and it can no longer be accessed
m_defaultLayer is destroyed
m_stack is destroyed
m_layers[0].onDetach() is called
onDetach sets m_app->m_activeObj to nullptr, but its lifetime has already ended, so behavior is undefined.
Irrelevant other stuff; you're already screwed.
The solution is to reorder things so that you don't access m_activeObj after its lifetime has ended. Either move m_stack's declaration after m_activeObj so it gets destroyed first or clear it manually in ~App.
according to the code bellow, is myClass1 object and myClass2 obj (which is the myClass1 object's member ) moving to the new thread with their memory(Like std::move()) ?
class myClass1{
public:
myClass2 obj;
myClass1(myClass2 * obj) {
this.obj = *obj;
}
thread spawn() {
return std::thread([this] { this->Run(); });
}
void Run() {
cout << "new thread" << endl;
}
}
myClass2{
public :
string str;
MyClass2(string str){
this.str = str;
}
}
int main(){
myClass1 object(new myClass2("test"));
thread t = object.spawn();
t.join();
........
}
As it stands, your main will call std::terminate, because you discard a joinable std::thread.
If you join it, main will block until the thread has finished. object will remain alive for the entire duration of Run.
If you detach it, main may end before the thread does, object will cease to exist and the this in myClass1::Run will be invalid. Undefined Behaviour.
A tidy up of your code
class myClass1 {
myClass2 obj;
public:
// Take by rvalue, uses the move constructor for obj
myClass1(myClass2 && obj) : obj(obj) {}
std::thread spawn() {
return std::thread([this]
{
// This is suspicious, but safe
auto self = std::move(*this);
self.Run();
});
}
void Run() {
std::cout << "new thread" << std::endl;
}
}
int main(){
// new is not required
myClass1 object(myClass2("test"));
object.spawn().join();
/* other stuff, not involving object */
return 0;
}
Even more of a tidy up
class myClass1 {
myClass2 obj;
public:
// Take by rvalue, uses the move constructor for obj
myClass1(myClass2 && obj) : obj(obj) {}
void Run() {
std::cout << "new thread" << std::endl;
}
}
int main() {
// Just create the instance of myClass1 as a parameter to `std::thread`'s constructor
std::thread(&myClass1::Run, myClass1(myClass2("test"))).join();
/* other stuff */
return 0;
}
No; creating a thread does not magically make the thread take ownership of that memory. If you create an object on the stack, create a thread that uses it; and then unwind the stack, destroying the object; with the thread still running, you will have undefined behaviour.
If you want to give ownership of some data to the thread, the easiest way to do it is with a shared pointer.
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 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;
}
}