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.
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 am trying to code two classes FooFactory and Foo. FooFactory initializes an object ToolBox in the constructor and stores it in a unique_ptr as I want that to be cleaned after the factory is destructed. All the instances of Foo should be able to use ToolBox so I am passing ptr to ToolBox object in the constructor of Foo and storing it as bare ptr.
I am new to c++ development so, my questions in the light of general suggestion I heard :
avoid raw pointers when possible
Is the usage of bare ptr to store the tool_box object that Foo doesn't own fine in this case? or Can I do better using smart_ptr?
Is the pattern of passing the ptr to ToolBox from the FooFactory class to every new object the correct or is there something better I can do?
Pseudo-code for my classes:
class FooFactory {
public:
FooFactory() {
tool_box_.reset(new ToolBox());
}
std::unique_ptr<Foo> NewFoo() {
std::unique_ptr<Foo> foo(new Foo(tool_box_.get());
return foo;
}
std::unique_ptr<ToolBox> tool_box_;
}
class Foo {
public:
Foo(ToolBox* tool_box) {
tool_box_ = tool_box;
}
private:
// Not Owned
ToolBox* tool_box;
}
A factory would normally never control the lifetime of an object. It should hand out an appropriate pointer, preferably a std::unique_ptr and the caller determines it's lifetime.
#include <string>
#include <iostream>
#include <memory>
class Box
{
public:
Box() {}
};
class Foo
{
public:
Foo(std::shared_ptr<Box> &box)
: m_box(box)
{
}
virtual ~Foo(){}
void print()
{
std::cout << "Hello World" << std::endl;
}
protected:
Box *getBox()
{
return m_box.get();
}
private:
std::shared_ptr<Box> m_box;
};
class FooFactory
{
public:
FooFactory()
{
m_box = std:make_shared<Box>();
}
std::unique_ptr<Foo> CreateFoo()
{
return std::make_unique<Foo>(m_box);
}
private:
std::shared_ptr<Box> m_box;
};
int main()
{
FooFactory factory;
std::unique_ptr<Foo> foo = factory.CreateFoo();
foo->print();
return 0;
}
One way to store a non-owning "pointer" to an object (while coupling the class with that object) would be to store a reference (or perhaps a const reference) instead of a pointer.
In my experience, the constraint of needing to initialize the class with that reference helps hierarchical design and simplifies lifetime management.
I need a way to provide different interfaces from a single object.
For example. User one should be able to call Foo::bar() and user 2 should be able to call Foo::baz() but user one cannot call Foo::baz() and respectively user two cannot call Foo::bar().
I did manage to do this but I don't think that it's optimal.
class A
{
public:
virtual void bar() = 0;
virtual ~A() = 0;
};
class B
{
public:
virtual void baz() = 0;
virtual ~B() = 0;
};
class Foo : public A, public B
{
public:
Foo() = default;
void baz() override;
void bar() override;
};
class Factory
{
public:
Factory()
{
foo = std::make_shared<Foo>();
}
std::shared_ptr<A> getUserOne()
{
return foo;
}
std::shared_ptr<B> getUserTwo()
{
return foo;
}
private:
std::shared_ptr<Foo> foo;
};
Is there a better way to achieve this. Maybe with wrapper objects. I don't really need to allocate this foo object with new(std::make_shared) I even prefer not to, but I cannot use raw pointers and smart pointers give unnecessary overhead and system calls.
Edit: I'll try to give an example.
There is a car. User one is the driver. He can steer the wheel, accelerate or use the breaks. User two is the passenger and he can control the radio for example.
I don't want the passenger to be able to use the breaks or the driver to be able to use the radio.
Also they are both in the car so the actions of user one will have effect on user two and vice versa.
What you essentially need is a shared data between two objects. The inheritance is not a very good choice for this because not only you do not need is A relationship but you explicitely want to avoid it. Therefore composition is your answer, especially since you have a factory:
class Data
{
public:
void bar();
void baz();
};
Then instead of inheritance you would use composition:
class A
{
public:
A(Base *base) : mBase(base) {}
void bar() { mBase->bar(); }
private:
Base *mBase = nullptr;
};
//class B would be the same only doing baz()
Finally the Factory:
class Factory
{
public:
A *getUserOne() { return &mA; }
B *getUserTwo() { return &mB; }
private:
Base mBase;
A mA(&mBase);
B mB(&mBase);
};
Couple of points about this solution. While it does not allocate on the heap you will need to keep the Factory alive as long as there are users of it. For this reason the use of std::shared_ptr as in the OP might be a smart idea. :-) But comes of course with the cost of the atomic reference counting.
Secondly A is not related to B in any way. This is by design and unlike the original solution does not allow dynamic_cast between A and B.
Lastly where the implementation will be is up to you. You can have it all in Data and have A and B merely call it (as in above) but you can also make Data into just a struct holding only your data and have the implementation of your methods in A and B respectively. The latter is more "data oriented" programming that has a lots of popularity these days as opposed to more traditional "object oriented" which is what I chose to demonstrate.
You can declare your data separately
struct Data
{
/* member variables */
};
Have an interface class capable of manipulating said data will all members protected
class Interface
{
protected:
Interface(Data &data) : m_data{data} {}
void bar() { /* implementation */ }
void baz() { /* implementation */ }
Data &m_data;
};
Have derived classed that make public specific members
class A : private Interface
{
public:
A(Data &data) : Interface{data} {}
using Interface::bar;
};
class B : private Interface
{
public:
B(Data &data) : Interface{data} {}
using Interface::baz;
};
This way you can also have users capable of having overlapping access to some functionality without having to implement it multiple times.
class Admin : private Interface
{
public:
Admin(Data &data) : Interface{data} {}
using Interface::bar;
using Interface::baz;
};
Of course, depending on how you're using the data, you might want a pointer or shared pointer, possibly add some syncronization between accesses from multiple threads.
Sample code using this model:
void test()
{
Data d{};
auto a = A{d};
a.bar();
// a.baz is protected so illegal to call here
auto b = B{d};
b.baz();
// b.bar is protected so illegal to call here
auto admin = Admin{d};
admin.bar();
admin.baz();
}
This seems to me efficient in the sense that you only have one set of data and a single implementation for data manipulation, no matter how many user types you have.
I have the following problem:
class Component
{
public:
virtual void update(){};
};
class TestComponent : public Component
{
void update()override;
};
class GameObject
{
public :
void addComponent(Component& comp)
{
std::shared_ptr<Component> test = std::make_shared<Component>(comp);
components.push_back(test);
}
void GameObject::update()
{
for(auto comp : components)
{
//I want to call the derived update here without casting it to the derived class if possible
comp->update();
}
}
private:
std::vector<std::shared_ptr<Component>> components;
};
Somewhere else in my code:
GameObject go;
TestComponent comp;
go.addComponent(comp);
I would just assume that when I add an object to the vector of Components that I can simply call update on all of the vectors elements and it uses the overridden update of the object I passed into addComponent. So for my example above I expect the forloop to call the update of the TestComponent I added and not the baseclass update. But thats not whats happening so I assume I am missing something.
Or maybe my approach is just wrong in general. I am not really sure about my usage of a sharedpointer for this?
Any hints in the right direction would be appreciated.
There are no TestComponent objects in your vector. They are all Components.
void addComponent(Component& comp)
{
std::shared_ptr<Component> test = std::make_shared<Component>(comp);
components.push_back(test);
}
In this function, you create a new Component object that s a copy of the Component sub-object of the TestComponent object you passed in. This is known as object slicing.
You will need to either avoid copying the objects or implement some sort of cloneable interface.
To avoid copying the object, you can do something like this:
class GameObject
{
public:
void addComponent(std::shared_ptr<Component> comp)
{
components.push_back(comp);
}
// ...
};
int main() {
GameObject go;
std::shared_ptr<TestComponent> testComponent = std::make_shared<TestComponent>();
go.addComponent(testComponent);
}
In this case, main and go share ownership of a single TestComponent object. If you want to avoid that, you could implement a clonable interface so that objects know how to copy themselves:
class Component
{
public:
virtual void update(){};
virtual std::shared_ptr<Component> clone() const
{
return std::make_shared<Component>(*this);
}
};
class TestComponent : public Component
{
void update() override;
std::shared_ptr<Component> clone() const override
{
return std::make_shared<TestComponent>(*this);
}
};
class GameObject
{
public:
void addComponent(const Component& comp)
{
components.push_back(comp.clone());
}
// ...
};
int main()
{
GameObject go;
TestComponent comp;
go.addComponent(comp);
}
In this case, you still make a copy, but every class has to override the clone method.
As for the question about shared_ptr: std::shared_ptr is a smart pointer that shares ownership of an object between multiple owners. An object owned by one or more std::shared_ptrs is only destroyed when all of the std::shared_ptr objects sharing ownership of it are destroyed. If you don't need this behavior, then std::unique_ptr exists and will be somewhat more performant. std::unique_ptr models unique ownership. Only one std::unique_ptr object can ever reference an object at a time, and the object is destroyed when that std::unique_ptr is destroyed.
Either type of smart pointer could be used in this situation:
Use std::shared_ptr if you want a GameObject to be able to share ownership of its components with other owners (perhaps other GameObjects).
Use std::unique_ptr if you want a GameObject to have exclusive ownership of its components. In this case the GameObject could still allow other objects to access its components, but the components' lifetimes would be tied to the lifetime of the GameObject
To make your code compile just add another method, rest are fine . Since update method is virtual and the base class is non-abstract, both can call update without any issue.
void TestComponent::addComponent(const TestComponent & tcomp)
{
std::shared_ptr<Component> test = std::make_shared<TestComponent >(tcomp);
components.push_back(test);
}
Edited: For adding any component, derived or base class, use this way:
void TestComponent::addComponent(std::shared_ptr<Component> comp)
{
components.push_back(comp);
}
I'm working on a couple of classes and I'm wondering how I can use a normal member in my application class, where the member needs to use shared_from_this()?
Here is some code to clarify what I mean (see comments)
class Observable {
public:
void addObserver(boost::shared_ptr<Observer> observer) {
// add to a list
}
};
class Observer {
public:
virtual void onUpdate() = 0;
};
class MyObservableType : public Observable {
};
class ApplicationModel : public Observer {
private:
MyObservableType mot;
public:
void setup() {
// how do I pass this as a boost::shared_ptr, as ApplicationModel is not
// a boost::shared_ptr in the Application class this using a call to
// "shared_from_this()" (and inheriting public shared_from_this<ApplicationModel>
mot.addObserver([shared_from_this])
}
};
class Application {
private:
ApplicationModel model;
public:
void setup() {
model.
}
};
You have three solutions to this problem:
First solution: force the application to create a shared_ptr by making its constructor private. This is what I would recommend to do for any class that derivates from enable_shared_from_this
class ApplicationModel : public Observer, public boost::enable_shared_from_this<ApplicationModel> {
private:
ApplicationModel(); // private constructor
MyObservableType mot;
public:
// an instance of this class can only be created using this function
static boost::shared_ptr<ApplicationModel> buildApplicationModel() {
return boost::make_shared<ApplicationModel>();
}
void setup() {
mot.addObserver(shared_from_this()) ;
}
};
Second solution: change your code design.
You should not ask the ApplicationModel to register itself to the Observable, but do it yourself. This way the ApplicationModel doesn't enforce anything, but if its owner wants to call addObservable, it has to create a shared_ptr. This is more or less what is called dependency injection.
class Application {
private:
boost::shared_ptr<ApplicationModel> model;
MyObservableType mot;
public:
void setup() {
model = boost::make_shared<ApplicationModel>();
mot.addObserver(model);
}
};
EDIT: Third solution: use a dummy shared_ptr, like this:
class ApplicationModel : public Observer {
private:
boost::shared_ptr<ApplicationModel> myself;
MyObservableType mot;
public:
void setup() {
mot.addObserver(myself) ;
}
ApplicationModel() {
myself = boost::shared_ptr<ApplicationModel>(this, [](ApplicationModel*) {});
}
~ApplicationModel() {
mot.removeObserver(myself);
assert(myself.unique());
}
};
The idea is to create a shared_ptr to this and to tell shared_ptr not to call the destructor (here I use an empty lambda function but you can easily create an inline structure). This is a hack and you shouldn't do so.
You can't. shared_from_this() requires that your object be allocated dynamically via a shared_ptr.
See this page of the documentation, which states:
Requires: enable_shared_from_this must be an accessible base class of T. *this must be a subobject of an instance t of type T . There must exist at least one shared_ptr instance p that owns t.
So you would need to alter your code to have any instances of ApplicationModel be "owned" by a shared_ptr. For example:
class ApplicationModel :
public Observer,
public boost::enable_shared_from_this<ApplicationModel>
{
//...
void setup() {
mot.addObserver(shared_from_this());
}
};
class Application {
private:
// Application object must initialize this somewhere
boost::shared_ptr<ApplicationModel> model;
//...
};