I have a mother class that stores the pointers to some objects in a list. I want these objects to detach themselves from the list when they are destroyed.
Can anyone suggest some good ways to do this please?
The crude way is to store the container reference (or pointer) in the objects in the list and remove themselves in their destructors:
class Contained;
class Container {
std::list<Contained*> children;
public:
...
void goodbye(Contained*);
};
class Contained {
Container& c; // you set this in the constructor
public:
~Contained() { c.goodbye(this); }
};
Note that this makes the Contained class non-copyable.
The easy way is to use some framework that already provides such functionality. Eg. if you use Qt, you would just derive the Contained class from QObject and store QPointer<Contained> in the Container. The QPointer would be set to zero once the contained object is deleted.
Or, if you use some memory management facilities like boost::shared_pointer, (I assume the Container doesn't own the Contained objects, otherwise, it knows best when the child object dies), you would use a weak pointer in the Container, which has similar functionality.
you can add reference/pointer to the mother class in those classes and when destructor is called they call mother.Detach(this)
Related
I'm trying to store references to objects that inherit from a nested abstract base class inside a std::set in the outer class.
Let me show you the code first since I think that's much more clear:
Class.h interface:
#ifndef Class_H_
#define Class_H_
#include <set>
#include <memory>
class Class
{
public:
class AbstractBase;
private:
std::set< std::shared_ptr<AbstractBase>> set;
public:
Class();
~Class();
void add(AbstractBase& object);
};
#endif
Abstract.h interface:
#ifndef ABSTRACT_H_
#define ABSTRACT_H_
#include "Class.h"
class Class::AbstractBase
{
friend class Class;
public:
virtual ~AbstractBase();
private:
virtual void foo(int in) = 0;
};
#endif
Derived.h interface:
#ifndef DERIVED_H_
#define DERIVED_H_
#include "Class.h"
#include "AbstractBase.h"
class Derived : private Class::AbstractBase
{
public:
~Derived() override;
private:
void foo(int in) override;
};
#endif
add.cc implementation:
#include "Class.h"
#include "AbstractBase.h"
void Class::add(AbstractBase& object)
{
// create a shared pointer to object
// and insert it in the set
set.insert(std::make_shared<AbstractBase>(object)); // <-- this is where it fails
}
So I would have multiple different derived objects all inheriting from AbstractBase which need to be stored together in the std::set container.
Compilation fails because of the pure virtual function. At first, I didn't use the std::shared_ptr and thought that this was the reason for failure, I found this SO answer suggesting to use a std::shared_ptr instead. I'm still getting a compilation error in Class::add because AbstractBase::foo is pure, but I thought the std::shared_ptr would solve this?
I found similar questions but nothing that helped me solve my specific problem. Could someone explain to me what I'm doing wrong?
Thank you.
EDIT: Wow! Thanks for the informative answers, I'll need some time to thoroughly understand them all and see what works best for me. I'll update this question once I'm done!
What your function attempts to do is make a copy of an object, allocate a shared instance for the copy, and store pointer to the copy.
Since your intention is to "store references" in the set, you presumably intend to store the objects elsewhere and don't actually want copies. If those referred objects are shared, then the correct solution is to pass the shared pointer:
void Class::add(std::shared_ptr<AbstractBase> ptr)
{
set.insert(std::move(ptr));
}
If the referred objects aren't shared, then you cannot refer to them with a shared pointer. You can use a non-owning pointer instead:
std::set<AbstractBase*> set;
void Class::add(AbstractBase* ptr);
However, be very careful with the non-owning approach to keep the referred objects alive at least as long as they are referred by the set. This is non-trivial. Reference can be used as an argument to add, but I recommend against this, since it may not be obvious to the caller that the function will store pointer to the argument for longer than the functions execution.
If you do want to copy, then you can use a virtual function that returns a shared pointer. Example:
class Class::AbstractBase
{
public:
virtual std::shared_ptr<AbstractBase> copy() = 0;
// ...
class Derived : private Class::AbstractBase
{
public:
std::shared_ptr<AbstractBase> copy() override {
auto ptr = std::make_shared<Derived>(*this);
return {ptr, static_cast<Class::AbstractBase*>(ptr.get())};
}
// ...
void Class::add(AbstractBase& object)
{
set.insert(object.copy());
To avoid repeating the identical copy in multiple derived types, you can use CRTP.
If you want to copy a class of unknown dynamic type, there are three well-known ways to get around having insufficient information:
Have a way to map the object to a handler expecting that specific most-derived type. typeid, a member-function, or a data-member in the common base-class which is its static type is most often used. This costs time, and is cumbersome to set up, but at least you often don't have to modify the class or use fat pointers.
Have a function to .clone() the object in the statically known base. This is known as the virtual constructor idiom, and generally the most efficient and convenient to set up.
Lug around an extra-pointer for cloning. This is the least invasive to the type or regarding additional setup, but changes the interfaces.
Which is most appropriate is yours to decide.
That is, if you actually want to copy the object, and shouldn't have passed a shared_ptr to .add() instead.
You need to clarify the ownership of the objects stored in the set. If you use std::shared_ptr, you fundamentally encode that the set inside each Class owns the contained instances. This is incompatible with an add(AbstractBase&) method - you cannot really take ownership of an arbitrary object by reference. What if this object is already managed by a different shared_ptr?
Maybe you actually only want to store copies in the set. In that case, see the other answer(s) for ways to polymorphically copy ("clone") objects.
It is also open why you want to use std::set. std::set establishes uniqueness of the contained objects using the < operator (or a user-provided comparison functor with equivalent semantics). Do you even want uniqueness? If so, based on what criteria? Currently, there is no way to compare the stored class objects. std::shared_ptr "solves" that problem by instead comparing the internal pointer values, but I doubt that's what you need here.
If you actually want to store and compare objects solely based on their memory locations and not assume ownership of the stored objects, you could just use raw pointers. If you only want to store a whole bunch of objects without caring about uniqueness (since you currently attempt to create copies, each stored element would have a unique address and thus you currently would never use that aspect of std::set), maybe std::vector is the better solution. std::set may also help with determining whether an object is present in the collection efficiently, but std::vector can do that just the same (and possibly faster, if you sort and binary search). Consider the advice in http://lafstern.org/matt/col1.pdf.
Basically i have a one struct that contains objects to share between classes as following;
struct CoreComponents
{
std::unique_ptr<a> m_A = std::make_unique<a>();
std::unique_ptr<b> m_B;
std::unique_ptr<c> m_C = std::make_unique<c>();
};
And in my main class i own it via unique_ptr;
class Game
{
...
private:
std::unique_ptr<CoreComponents> m_Components;
...
};
Then i have other n classes which i need to access that m_Components object from it's functions without creating copies. (i will not modify contents of that object)
I tried using shared_ptr to hold m_Components in Game class then pass it to other classes (to their constructors) via value and store it but that scenario causes memory leaks. (i use memcheck for checking leaks) I found out that it's the cause of the leak but i couldn't figure out why exactly.
Shared_ptr scenario
Constructor of class which i need to access CoreComponents object;
GameScene::GameScene(std::shared_ptr<CoreComponents> components)
: m_Components(std::move(components))
I'm trying to hold it as member of GameScene class then use it in functions;
std::shared_ptr<CoreComponents> m_Components;
And this is how i pass it from inside of the Game class;
auto gs = std::make_unique<GameScene>(m_Components)
General usage inside GameScene class;
m_Components->m_A->draw(*m_OtherObjectInsideGameScene);
So what is the best way to create similar design using modern c++?
I was trying to avoid Singleton pattern but do i have to use it to achieve this or it's possible with better smart pointer usage?
PS: CoreComponents struct needs to be deleted from memory when Game class is destroyed.
It seems that you correctly separate the concerns of ownership and usage. The only trouble you have is how to forward the components to the rest of your system.
I would keep your owning structure, and create dedicated structures for the specific users:
struct CoreComponents {
unique_ptr<A> a; unique_ptr<B> b; ...
};
struct PartOfTheSystem {
void use(A& a, B& b);
};
struct Game {
CoreComponents components;
PartOfTheSystem user;
void stuff() {
user.use(*components.a, *components.b);
}
};
Yes: more typing.
But also: very clear logic: construction/ownership and use are separate concerns, and this is perfectly clear by design! Also refer to https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-smartptrparam.
The best way if you have shared objects is indeed to use a shared_ptr.
A unique_ptr is for unique ownership.
If you had memory leaks, it's time to investigate why that was, and fix them! Your report suggests a cyclical reference. Check for accidental lambda capture, and in some places you perhaps meant to use weak_ptr instead.
Using a singleton for this is like fixing your car's broken tyre by setting the whole thing on fire and taking a donkey instead. Your unique_ptr approach is more like fixing your car's broken tyre by removing it and driving on rims for the lols.
I want to create a collection in C++ of type Parent, where I add different subclasses like Child and Child2, and then get all the elements of X subclass. I tried with a vector, but it happens to destroy polymorphism according to this answer. If I use a collection of pointers, I would have to iterate over it sequentially checking the class of every element, is there a better / more efficient solution?
Here's an example code:
class Parent
{
public:
int id;
Parent(){ id = 8; }
};
class Child: public Parent
{
int foo;
public:
Child(int n){ foo= n; }
};
class Child2: public Parent
{
int bar;
public:
Child2(int n){ bar= n; }
};
Pseudocode:
GenericCollection<Parent> collection; //Full of elements Child and Child2.
This is the method I want to implement:
collection.getElements<Child2>();
Thanks for everything.
You cannot do this with objects because of the object slicing problem. You need to use pointers instead - preferably, smart pointers, such as unique_ptr<Parent>:
GenericCollection<unique_ptr<Parent>> collection;
Now you can implement your getElements method that uses Run-Time Type Information (RTTI) to detect the type of the object pointed to by the smart pointer, and keep only the ones pointing to Child2.
Note that in order to use RTTI your base class Parent needs to have at least one virtual member function. This shouldn't be an issue in your case, because you expect polymorphic behavior.
In C++ you can't directly do what you're asking, because items are stored "by value" in the vector, so you'll only end up with the parent portion of each object while the child-specific parts will be sliced away.
However we may be able to solve your real problem.
If you really need to be able to generate separate lists of child1 and child2 objects, the C++ idiom would be separate vectors to contain each different type.
If however all you need is polymorphism, then you could have a vector of (smart) pointers to the base class, and operate on those polymorphically. If you take this approach don't try to get a list of a specific child's objects but instead utilize an appropriate abstract interface to perform your logic.
In this case you can't. Read about object slicing for more information.
It will only work if you have a collection of pointers. For this I recommend you read about std::unique_ptr.
I want my code to be extensible, in a way where at runtime I create the objects.
For example, let's say I have a Grocery class which has an array of fruits and I want to fill this array of fruits with objects which derives from fruits.
class Fruit{
};
class Grocery{
std::vector<Fruit*> m_fruits;
};
class Apple: Fruit{
};
class Pineapple: Fruit{
};
Now at runtime I want my Grocery class vector m_fruits to be filled with class objects of Apple and Pineapple. So is it possible in some way.
if I add another fruit as strawberry in future, its object will be created and added to the vector of Grocery dynamically without changing the implementation of Grocery class?
Code help will be appreciated.
Check your textbook. It probably mentions that you can only treat pointers to types polymorphically. In other words, a vector of pointers to fruit can take pointers to apples or pineapples.
Well, if you want to make it so your Grocery class can generate any type of fruit. Even fruit that has been implemented after the grocery class has been locked away, I suppose you might be after something like the following?
typedef Fruit*(*FruitInstantiatorPtr)();
template<class T>
Fruit* FruitInstantiator()
{
return new T();
}
// Then in Grocery have a function like:
static void AddFruitGenerator(FruitInstantiatorPtr instantiatorFunc, string fruitTypeName);
////
//Then someone somewhere can go:
class MyNewFruit:Fruit{};
MyGrocery.AddFruitGenerator(FruitInstantiator<MyNewFruit>, "myAwesomeNewFruit");
And that way your Grocery class will be able to instantiate any type of fruit added in the future.
Assum that Fruit has pure virtual functions (denoted by virtual func() = 0) you would need to store pointers to Fruit objects inside your vector std::vector<Fruit*>.
Unfortunately standard containers aren't particulary good at handling pointers and you will have to delete all objects inside your vector in the destructor of your Grocery. You might consider shared_ptr from TR1 or the boost library.
A word on naming: Instantiation isn't the proper word in this case.
You cannot store objects of a derived type by value in any container of a base type without object slicing occuring.
You need to do one of the following:
Use a vector of raw pointers to the base type, e.g. std::vector<Fruit*> and manage the lifetime of the individual Fruit instances yourself (this is the least desirable option).
Use a vector of smart pointers to the base type, e.g. std::vector<boost::shared_ptr<Fruit> >, and allow reference counting to manage the individual items' lifetimes.
Use boost::ptr_vector<Fruit> to store the items, and the items' lifetime are bound to that of the containing ptr_vector.
Depending on your need, #2 & #3 are preferable. #1 should be avoided, as it involves manual effort to manage the lifetimes and could easily result in memory leaks if done incorrectly.
I have a c++ class derived from a base class in a framework.
The derived class doesn't have any data members because I need it to be freely convertible into a base class and back - the framework is responsible for loading and saving the objects and I can't change it. My derived class just has functions for accessing the data.
But there are a couple of places where I need to store some temporary local variables to speed up access to data in the base class.
mydata* MyClass::getData() {
if ( !m_mydata ) { // set to NULL in the constructor
m_mydata = some_long_and complex_operation_to_get_the_data_in_the_base()
}
return m_mydata;
}
The problem is if I just access the object by casting the base class pointer returned from the framework to MyClass* the ctor for MyClass is never called and m_mydata is junk.
Is there a way of only initializing the m_mydata pointer once?
It doesn't have members and you must maintain bit-for-bit memory layout compatibility… except it does and C++ doesn't have a concept of freely-convertible.
If the existing framework allocates the base objects, you really can't derive from it. In that case, I can think of two options:
Define your own class Cached which links to Base by reference. Make the reference public and/or duplicate Base's interface without inheritance.
Use a hash table, unordered_map< Base *, mydata > mydata_cache;. This seems most appropriate to me. Use free functions to look up cache data before delegating to the Base *.
You could initialize your private variables in a separate initialization member function, so something like this:
class MyClass {
public:
init() {
if (!m_mydata) {
m_mydata = f();
}
}
};
framework_class_t *fclass = framework.classfactory.makeclass();
MyClass *myclass = (MyClass*)fclass;
myclass->init();
char *mydata = myclass->getData();
It's hard to say if this is a good idea or not without knowing what framework you're using, or seeing your code. This is just the first thing that came to mind after reading your description.
You could create a wrapper for the factory of the framework. The wrapper would have the same interface, delegate calls to the framework but it could initialize the created base class instance before returning it. Of course, this requires you to change your code to use the wrapper everywhere, but if it is possible, after that you can be sure that the initialization happens properly.
A variation on this: use RAiI by wrapping the base class instances into a custom autopointer which could do the initialization in its constructor. Again, if you manage to change the code everywhere to use the new wrapper type instead of the derived class directly, you are safe.