Note: Before posting the question, I have gone through the existing questions on std::bad_weak_error while using shared_from_this to pass the shared_ptr of the existing shared_ptr instance to another method. None of them are similar to this as:
There is already an existing shared_ptr instance of the class created before trying to call shared_from_this()
The class inherits from std::enable_shared_from_this<> publically.
Here is the sample code to reproduce the error:
#include <iostream>
#include <memory>
class ILogger {
public:
virtual ~ILogger() {}
virtual void Log() = 0;
};
class LogManager;
class Logger : public ILogger {
public:
Logger(std::shared_ptr<LogManager> logManager)
: m_logManager(logManager)
{
}
void Log() override
{
std::cout << "Dump logs";
}
private:
std::shared_ptr<LogManager> m_logManager;
};
class ILogManager {
public:
virtual ~ILogManager() {}
virtual std::shared_ptr<ILogger> GetLogger() = 0;
};
class LogManager : public ILogManager, public std::enable_shared_from_this<LogManager> {
public:
virtual std::shared_ptr<ILogger> GetLogger()
{
return std::static_pointer_cast<ILogger>(std::make_shared<Logger>(this->shared_from_this()));
}
};
class LogManagerFactory {
public:
static ILogManager* Create()
{
auto logManager = new LogManager();
return logManager;
}
};
int main()
{
auto logManager = std::shared_ptr<ILogManager>(LogManagerFactory::Create());
auto logger = logManager->GetLogger();
}
The error:
Program returned: 139
terminate called after throwing an instance of 'std::bad_weak_ptr'
what(): bad_weak_ptr
Link to code: https://godbolt.org/z/GTcafM449
In order for the enable_shared_from_this subobject to be initialized, the shared_ptr constructor needs to know that the class in question inherits from enable_shared_from_this. Look at the expression that creates the shared pointer:
std::shared_ptr<ILogManager>(LogManagerFactory::Create());
The only class involved in this expression does not inherit from std::enable_shared_from_this<>. You are creating a shared pointer to ILogManager from a pointer to ILogManager. This is what the compiler generates code for – creating a shared_ptr for a class that does not inherit from enable_shared_from_this. The constructor is not aware that you are expecting it to initialize an enable_shared_from_this subobject.
The code works if you change the return type of LogManagerFactory::Create() from ILogManager* to LogManager*. You can keep the std::shared_ptr<ILogManager> part as long as the construction parameter brings LogManager into the picture.
Note: To be safer, LogManagerFactory::Create() should return either a unique_ptr or a shared_ptr instead of a raw pointer to clearly communicate that the caller gains ownership.
When you run:
std::shared_ptr<ILogManager>(LogManagerFactory::Create())
shared_ptr only knows the pointer is an ILogManager which doesn't have enable_shared_from_this so doesn't set the weak pointer.
The solution (and safer code in general) is to create the shared_ptr in Create at which point the constructor can see the true type and enable_shared_from_this will therefore work:
static std::shared_ptr<ILogManager> Create()
{
auto logManager = new LogManager();
return std::shared_ptr<ILogManager>(logManager);
}
Or more simply:
static std::shared_ptr<ILogManager> Create()
{
return std::make_shared<LogManager>();
}
Related
I am trying to encapsulate details of the Engine implementation class. To do that I am returning std::unique_ptr of abstract class (IEngine in my case) instead of Engine. But I could not do that due to the compile error. I could return raw reference and it works but is that possible with unique_ptr? Thanks in advance.
class IEngine
{
public:
virtual ~IEngine() = default;
virtual void Start() = 0;
};
class Engine : public IEngine
{
public:
void Start() override {}
};
class Car
{
std::unique_ptr<Engine> m_engine;
public:
std::unique_ptr<IEngine>& Get() { return m_engine; } // Here is compile error
};
int main()
{
Car lambo;
}
std::unique_ptr<IEngine> is a different type to std::unique_ptr<Engine>, so you are asking to return a reference to a temporary object.
std::unique_ptr uniquely owns the object it points to, so even if you removed the reference, it would be incorrect to create a std::unique_ptr<IEngine> from the existing std::unique_ptr<Engine> that you presumably want to leave unchanged.
You shouldn't be exposing std::unique_ptr here. I'm not really sure you should be exposing IEngine here. I'm also confused as to why you need the concrete Engine type in Car, but the outside world needs mutable access to a pointer to IEngine.
I would instead expect something like:
class Car
{
std::unique_ptr<IEngine> m_engine;
public:
void TurnIgnition() { m_engine->Start(); }
};
I am trying to encapsulate details of the Engine implementation class.
Returning a non-const reference to a private member is rarely the right thing to do. In any case it is the opposite of data encapsulation. Once the caller has the reference they can do with it whatever they like. Returning a non const reference makes sense for convenience access methods like for example std::vector::operator[]. The purpose of std::vector::operator[] is not to hide the element from the caller. There are other ways to get your hands on it. Rather std::vector::operator[] is to make it more convenient to access elements. Encapsulation it is not.
It is also not clear why you want to return a unique_ptr from Get. When no transfer of ownership is desired no smart pointer needs to be returned.
I could return raw reference
Yes, thats perfectly fine:
#include <memory>
class IEngine
{
public:
virtual ~IEngine() = default;
virtual void Start() = 0;
};
class Engine : public IEngine
{
public:
void Start() override {}
};
class Car
{
std::unique_ptr<Engine> m_engine;
public:
const IEngine& Get() { return *m_engine; } // Here is compile error
};
int main()
{
Car lambo;
}
I have the following class structure for Managing callbacks with different prototypes:
class MethodHandlerBase: public std::enable_shared_from_this<MethodHandlerBase>{
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA: public MethodHandlerBase{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
class MethodHandlerB: public MethodHandlerBase{
private:
MethodHandlerBCallback cb;
public:
MethodHandlerB(MethodHandlerBCallback cb): cb(cb){}
virtual void operator()(void* data);
};
In some cases MethodHandlerA or MethodHandlerB might use this (wrapped in a shared_ptr) in a lambda expression passed to elsewhere, so I need to be sure that it is correctly deleted when needed. Therefore I added the std::enable_shared_from_this<MethodHandlerBase> inheritance to the base class.
But I read that you usally cannot use std::enable_shared_from_this via inheritance (apart from using a template, which actually would not really be inheritance anymore). In my understanding this is due to the possible wrongly destruction of the instance. In this case I would assume my code would work properly since it uses a virtual destructor (which is needed anyway).
So am I right with my theory or is there something else going on about std::enable_shared_from_this inheritance that I did not understand?
EDIT:
To add a short examples of what I plan to use it like:
From inside the class:
void MethodHandlerB::operator()(void* data){
std::shared_ptr<MethodHandlerB> thisPtr = std::dynamic_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr](){
thisPtr->doSomething();
});
}
and from outside
std::vector<MethodHandlerBase> vec{std::make_shared<MethodHandlerB>()};
Some minor points:
You could move the shared pointer into the lambda to avoid an atomic increment and decrement
No need to use a dynamic pointer cast since you know for sure the dynamic type (plus you don't check the result is not empty anyway!)
void MethodHandlerB::operator()(void* data){
auto thisPtr = std::static_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr = std::move(thisPtr)](){
thisPtr->doSomething();
});
}
Alternatively, you could use separate captures for this and the shared pointer, which avoids the cast altogether:
void MethodHandlerB::operator()(void* data){
putLamdaToSomeGlobalEventThing([this, thisPtr = shared_from_this()](){
doSomething();
});
}
Edit: as one of the comments points out, if you don't use shared_from_this() directly on the base class, you're better off just deriving from enable_shared_from_this in the derived classes. You can do this because C++ supports multiple inheritence.
class MethodHandlerBase {
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA:
public MethodHandlerBase,
public std::enable_shared_from_this<MethodHandlerA>
{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
void MethodHandlerA::operator()(void* data){
putLamdaToSomeGlobalEventThing([self = shared_from_this()](){
self->doSomething();
});
}
You can make a little helper class
template <class Base, class Derived>
struct enable_shared : public Base
{
std::shared_ptr<Derived> shared_from_this()
{
return std::static_pointer_cast<Derived>(
Base::shared_from_this());
};
};
Now you can use shared_from_this freely in all these classes. and it will return the correct type:
class Base : public std::enable_shared_from_this<Base> ...;
class Derived : public enable_shared<Base, Derived> ...;
class MoreDerived : public enable_shared<Derived, MoreDerived> ...;
By the way, if you use std::make_shared, then a virtual destructor is not needed, because the shared pointer is created with the right deleter for the most derive type. It is probably a good idea to define one anyway, just to be on the safe size. (Or maybe not.)
Coming from the Java/PHP world, I am still new to C++. Some simple things to do in other languages are a bit trickier to do in C++.
My main issue is the following. Right now, I have a class (ie. "Something") for which the constructor is injected with a virtual class dependency (ie. a children of "Base"). Then, the constructor stores this injected instance in a unique_ptr<Base> class field (using the clone idiom). This works well at the application level, everything seems to works as expected. Here is the sample code:
class Base {
public:
virtual std::unique_ptr<Base> clone() = 0;
virtual void sayHello() const = 0;
};
class Something {
public:
explicit Something(Base &base) { this->base = base.clone(); }
void sayHello() const { base->sayHello(); }
private:
std::unique_ptr<Base> base;
};
But to make sure it does, I wrote unit tests to test its behavior. In those tests, I want to assert the injected dependencies methods are actually called. So logically, injecting a "spy" dependency should do the trick.
Here is what I did at first:
class SpyDerived : public Base {
public:
explicit SpyDerived() = default;
SpyDerived(const SpyDerived &original) { this->someState = original.someState; }
std::unique_ptr<Base> clone() override { return std::make_unique<SpyDerived>(*this); }
void sayHello() const override { std::cout << "My state: " << someState << std::endl; }
void setSomeState(bool value) { this->someState = value; }
private:
bool someState = false;
};
This is the main function I use to this this out:
int main() {
SpyDerived derived;
Something something(derived);
derived.setSomeState(true);
something.sayHello();
}
For obvious reasons, someState value on print is always false. I get that the Derived instances in Something is a new copy of Derived and no longer the one that was created in the main function.
So basically, what I am trying to achieve here is to have the Something class always use the SpyDerived instance created in the main function. Is there any way I could make this work. I am trying to avoid changing the design just for test purposes.
I am using MSVC 2015 to compile the code. Keep in mind that smart pointers, C++ idioms, copy/move constructors are fairly new concepts for me.
Thanks for your help.
Well, do you want to clone your instance, or simply reference that instance?
The clone idiom is made to copy the instance of a class, making the new instance independent of the old instance.
You are basically making this, in term of PHP:
<?php
interface Base {
public function sayHello();
}
class SpyDerived implements Base {
private $someState = false;
public function sayHello() {
echo 'My state: ' . $this->someState;
}
}
class Something {
public __construct(Base $base) { $this->base = clone $base; }
public function sayHello() { $this->base->sayHello(); }
private $base = null;
}
$derived = new SpyDerived;
$something = new Something($derived);
$derived->setSomeState(true);
$something->sayHello();
?>
You see this? $base is cloned. Something::$base is a copy.
So in PHP, what would you do to solve that problem?
Simple! Remove that clone, no copies!
Well, in C++, this is the same thing. If you have an object pointer and don't want to clone it, don't actually call the clone method.
We will change your class to, like PHP, contain a reference to the object. We will start by making Something contain a non owning reference:
class Something {
public:
explicit Something(Base& b) : base{b} { }
void sayHello() const { base.sayHello(); }
private:
// we simply contain a reference to the base
Base& base;
};
In C++, a reference does not own the object. If the object is destroyed, all reference pointing to that object will point to a dead object.
As you can notice, your tests stays the same and work:
int main() {
SpyDerived derived;
Something something(derived);
derived.setSomeState(true);
something.sayHello();
}
If you want Something be the owner of Base, then use std::unique_ptr<Base>:
class Something {
public:
explicit Something(std::unique_ptr<Base> b) : base{std::move(b)} { }
void sayHello() const { base->sayHello(); }
private:
std::unique_ptr<Base> base;
};
Beware that the ownership of base should be transferred from the caller to the something class. That transfer is express through that std::move thing, because we are moving the ownership of that resource.
Then in your tests:
int main() {
auto derived = std::make_unique<SpyDerived>();
// We want to keep a non-owning reference of derived
// The star (*) operator of std::unique_ptr returns a reference to the pointed object
auto& derived_ref = *derived;
// We transfer the ownership of derived to the `Something`
Something something(std::move(derived));
// Since derived is a reference to the object pointed by our pointer,
// It will affect the value we found in `Something`, because they are
// both pointing to the same instance.
derived.setSomeState(true);
something.sayHello();
}
Since Something is owner of derived, the non-owning reference derived_ref will point to a dead object if something dies before.
I would like to implement a base object, which can autoregister itself into a singleton object list. I would store shared pointers pointing to these objects in the list. The registration would be good to happen either in the constructor or a separate initialisation function set(). My problem is that the object does not know it's shared pointer. How can I solve this problem?
The object:
class Object
{
public:
Object() {}
virtual ~Object() {}
void set()
{
// register object, how?
}
void unset() {
// unregister object, how?
}
};
The object list:
#include <memory>
#include <list>
class ObjectPool
{
public:
void unregisterObject(std::shared_ptr<Object> objPtr) {
objPtrList.remove(objPtr);
}
void registerObject(std::shared_ptr<Object> objPtr) {
objPtrList.push_back(objPtr);
}
private:
std::list<std::shared_ptr<Object> > objPtrList;
};
Usage:
int main()
{
auto objPtr = std::make_shared<Object>();
objPtr->set();
objPtr->unset();
}
I would not want to use the register/unregister methods of the container singleton directly, because
I want to hide this registering mechanism from user codes, and
set/unset functions do additional staff besides registering
I suspect that this problem may come from inadequate design so I'm interested in solutions with completely different designs also, if they can used for the same purpose.
Update: Solution
Deriving Object from std::enable_shared_from_this:
class Object : public std::enable_shared_from_this<Object>
{
public:
Object() {}
virtual ~Object() {}
void set()
{
ObjectPool.registerObject(shared_from_this());
}
void unset() {
ObjectPool.unregisterObject(shared_from_this());
}
};
Derive you Object from std::enable_shared_from_this.
So I have a couple classes defined thusly:
class StatLogger {
public:
StatLogger();
~StatLogger();
bool open(<parameters>);
private:
<minutiae>
};
And a child class that descends from it to implement a null object pattern (unopened it's its own null object)
class NullStatLogger : public StatLogger {
public:
NullStatLogger() : StatLogger() {}
};
Then I have a third class that I want to take an optional logger instance in its constructor:
class ThirdClass {
public:
ThirdClass(StatLogger& logger=NullStatLogger());
};
My problem is when I do it as above, I get:
error: default argument for parameter
of type ‘StatLogger&’ has type
‘NullStatLogger’
And if I put an explicit cast in the definition, I get:
error: no matching function for call
to
‘StatLogger::StatLogger(NullStatLogger)
Complaining about not having a constructor from a NullStatLogger even though it's a child class. What am I doing wrong here, is this allowed in C++?
I you want to use inheritance and polymorphism, ThirdClass needs to use either a pointer or a reference to StatLogger object, not with an actual object. Likewise, under the circumstances you almost certainly need to make StatLogger::~StatLogger() virtual.
For example, modified as follows, the code should compile cleanly:
class StatLogger {
public:
StatLogger();
virtual ~StatLogger();
// bool open(<parameters>);
private:
// <minutiae>
};
class NullStatLogger : public StatLogger {
public:
NullStatLogger() : StatLogger() {}
};
class ThirdClass {
StatLogger *log;
public:
ThirdClass(StatLogger *logger=new NullStatLogger()) : log(logger) {}
};
Edit: If you prefer a reference, the code looks something like this:
class StatLogger {
public:
StatLogger();
virtual ~StatLogger();
// bool open(<parameters>);
private:
// <minutiae>
};
class NullStatLogger : public StatLogger {
public:
NullStatLogger() : StatLogger() {}
};
class ThirdClass {
StatLogger &log;
public:
ThirdClass(StatLogger &logger=*new NullStatLogger()) : log(logger) {}
};
Based on the discussion in Jerry's answer, what about simplifying the problem by not using a default variable at all:
class ThirdClass
{
StatLogger log;
public:
ThirdClass() : log(NullLogger()) {}
ThirdClass(const StatLogger& logger) : log(logger) {}
};
There is no problem in using a derived instance as default argument for a base reference.
Now, you cannot bind a non-constant reference to a temporary (rvalue) which can be one reason for the compiler to complain about your code, but I would expect a better diagnose message (cannot bind temporary to reference or something alike).
This simple test compiles perfectly:
class base {};
class derived : public base {};
void f( base const & b = derived() ) {} // note: const &
int main() {
f();
}
If the function must modify the received argument consider refactoring to a pointer and provide a default null value (not a default dynamically allocated object).
void f( base * b = 0) {
if (b) b->log( "something" );
}
Only if you want to keep the non-const reference interface and at the same time provide a default instance, then you must provide an static instance, but I would recommend against this:
namespace detail {
derived d;
// or:
derived & null_logger() {
static derived log;
return log;
}
}
void f( base & b = detail::d ) {}
// or:
void g( base & b = detail::default_value() ) {}
Well for a default value I believe you have to provide a default value...
ThirdClass(StatLogger *logger = NULL)
for example
Uh, I know this is an oooold question, but I just had the exact same problem, and after reading all the proposed answers and comments, I came up with a slightly different solution.
I think it also might just be appropriate for the problem instance presented here, so here it goes:
Make the NullStartLogger a singleton type of object!
For me, it was quite elegant and sort. Very shortly, singleton is an object that you can not construct at will, since only and exactly one instance can exist at all time. (Alternatively, there might be 0 instances before the first usage, since you can postpone the initialization). You can of course only add the singleton functionality in to your derived class, while all the other instances (and derivations) of the parent class can be initialized and created normally. But, if NullStatLogger is, as it was in my case, just a dummy class, it does not store any data externally and does not have different behavior depending on the instance/init parameters, singleton class fits well.
Here's a short code snipped making your NullStatLogger a singleton, as well as a way to use it in the ThirdClass:
class NullStatLogger : public StatLogger {
private:
NullStatLogger() : StatLogger() {}
static NullStatLogger *_instance;
public:
static NullStatLogger &instance();
};
NullStatLogger::_instance = 0;
NullStatLogger &NullStatLogger:instance() {
if (_instance == 0)
_instance = new NullStatLogger(); // constructor private, this is
// the only place you can call it
return *_instance; // the same instance always returned
}
class ThirdClass {
public:
ThirdClass(StatLogger& logger=NullStatLogger::instance());
};
I know this surely won't help to whomever asked the question, but hopefully it helps someone else.