Is this a correct way of thinking about smart pointers and using raw pointers for non-ownership?
class DisplayObject {
DisplayObject* Parent;
};
class DisplayObjectContainer: public DisplayObject {
std::vector<DisplayObject*> Children;
};
class Stage {
std::vector<std::unique_ptr<DisplayObject>> DisplayObjects;
};
Items are created using
make_unique<DisplayObject>
or
make_unique<DisplayObjectContainer>
Stage would own all DisplayObject classes but a DisplayObjectContainer will have raw pointers to Stage's owned objects.
DisplayObject will also have a Parent (which can be nullptr).
I also take the Stage's DisplayObjects and get the pointer to it's object when I add the item to the vector (DisplayObjects.back().get()) and make heavy use of std::move
Is this a correct way of using smart pointers and ownership?
Looking at your code, yes. This looks like a perfectly good way to organize your code: you have a single class which is keeping explicit ownership, and every other class that uses raw pointers does not own what it is pointing at. This will keep your code clean, efficient, and everybody using it will know what breaks when, and how.
Just make sure if you do start to share this code around, you tell everyone upfront that raw pointers means it doesn't own resources, and that they are to not delete or new the resources themselves. Making this known upfront will prevent confusion on whether or not the pointers people use / pass to your methods need to be manually new'd.
Side note:
DisplayObject? DisplayObjectContainer? Sounds a lot like AS3's display hierarchy for C++! It sounds interesting. I wish you all the best.
Related
I have a class called Widget. This class is abstract and has virtual methods. To avoid object slicing all Widgets are stored as references or pointers. I have several classes with constructors that store internally the widget given to them; thus the Widget stored must have been initialized outside the constructor and cannot be destroyed before the object is, therefore usually the Widget is allocated via dynamic memory. My question is regarding how to handle this dynamic memory; I have compiled a list of options (feel free to suggest others.) Which is the most idiomatic?
1. Smart pointers. Smart pointers seem like the right choice, but since I'm using C++98 I have to write my own. I also think that writing smart_pointer<Widget> all the time is a little ugly.
2. Copy Widgets when stored. Another course of action is to store a copy of the passed-in Widget instead of the original. This might cause object-slicing, but I'm not sure. Also, users might want to write classes themselves that store passed-in Widgets, and I wouldn't want to make it too complicated.
3. Let the user handle everything. I could perhaps make the user make sure that the Widget is deleted on time. This seems to be what Qt does (?). However, this again complicates things for the user.
I personally like this approach (it is not always applicable, but I used it successfully multiple times):
class WidgetOwner
{
vector<Widget*> m_data;
public:
RegisterWidget(Widget *p) { m_data.push_back(p); }
~WidgetOwner() { for (auto &p : m_data) delete p; }
};
This simple class just stores pointers. This class can store any derivatives of Widget provided that Widget has virtual destructor. For a polymorphic class this should not be a problem.
Note that once Widget is registered, it cannot be destroyed unless everything is destroyed.
The advantage of this approach is that you can pass around pointers freely. They all will be valid until the storage will be destroyed. This is sort of hand made pool.
Which is the most idiomatic?
The most idiomatic would certainly be what next versions of c++ decided to be "the way to go", and that would be smart pointers (You can find/use an implementation on boost for example, also other ones on the internet might be simpler for inspiration).
You can also decide that since you are using c++98 (that's a huge factor to take into consideration), you take what's idiomatic for that context, and since that was pretty much no man's land, the answer is most likely whatever home made design is the most appealing to you.
I think smart pointer is best choice. And if you feel template is ugly, try the typedef
I'm having trouble getting things organized properly with smart pointers. Almost to the point that I feel compelled to go back to using normal pointers.
I would like to make it easy to use smart pointers throughout the program without having to type shared_ptr<...> every time. One solution I think of right away is to make a template class and add a typedef sptr to it so I can do class Derived : public Object < Derived > .. and then use Derived::sptr = ... But this obviously is horrible because it does not work with another class that is then derived from Derived object.
And even doing typedef shared_ptr<..> MyObjectPtr is horrible because then it needs to be done for each kind of smart pointer for consistency's sake, or at least for unique_ptr and shared_ptr.
So what's the standard way people use smart pointers? Because frankly I'm starting to see it as being too much hassle to use them. :/
So what's the standard way people use smart pointers?
Rarely. The fact that you find it a hassle to use them is a sign that you over-use pointers. Try to refactor your code to make pointers the exception, not the rule. shared_ptr in particular has its niche, but it’s a small one: namely, when you genuinely have to share ownership of a resource between several objects. This is a rare situation.
Because frankly I'm starting to see it as being too much hassle to use them. :/
Agreed. That’s the main reason not to use pointers.
There are more ways to avoid pointers. In particular, shared_ptr really only needs to spelled out when you actually need to pass ownership. In functions which don’t deal with ownership, you wouldn’t pass a shared_ptr, or a raw pointer; you would pass a reference, and dereference the pointer upon calling the function.
And inside functions you almost never need to spell out the type; for instance, you can (and should) simply say auto x = …; instead of shared_ptr<Class> x = …; to initialise variables.
In summary, you should only need to spell out shared_ptr in very few places in your code.
I have a lot of code that creates objects dynamically. So using pointers is necessary because the number of objects is not known from the start. An object is created in one subsystem, then stored in another, then passed for further processing to the subsystem that created it. So that I guess means using shared_ptr. Good design? I don't know, but it seems most logical to ask subsystem to create a concrete object that it owns, return a pointer to an interface for that object and then pass it for further processing to another piece of code that will interact with the object through it's abstract interface.
I could return unique_ptr from factory method. But then I would run into trouble if I need to pass the object for processing multiple times. Because I would still need to know about the object after I pass it to another method and unique_ptr would mean that I lose track of the object after doing move(). Since I need to have at least two references to the object this means using shared_ptr.
I heard somewhere that most commonly used smart pointer is unique_ptr. Certainly not so in my application. I end up with using shared_ptr mush more often. Is this a sign of bad design then?
Is it possible to store a bunch of objects by their base class in say an std::list without pointers. I would really like the objects to be held in the container, then retrieve a pointer to the object in the container and dynamic_cast it to correct derived class.
I have it working fine using pointers. Like (super simple version):
class IComponent
{
virtual ~Icomponent(){}
}
class PositionComponent: public IComponent
{
//...
float x, y;
}
std::list<IComponent*> CList;
//...
// fill the list
// put reference to object in pComponent
//...
PositionComponent* position = dynamic_cast<PositionComponent*>( pComponent)
position->x = 346452.235612;
But the memory management is a huge pain. My actual structure is a
map<enumValue, map<int, IComponent*> >
I get the feeling I can't use the objects themselves because when I add any derived component into the list the extra data will be cut off and leave me with the base class only. This didn't figure this until I tried static_cast instead and it crashed.
Can answer my original question and/or confirm my feelings on the matter. Thanks!
to minimize pain of manual memory management use smart pointers: std::unique_ptr if your compiler already supports it or boost::shared_ptr, but not std::auto_ptr that is not supposed to be used in containers
As you guessed, when you stored an object in a container by value, it gets sliced and the data is chopped off.
If you only need to store one data type (you only show one in your code), then you can make the container hold that type.
If not, you really are stuck using pointers. You can make the memory management much easier by using a smart pointer, or if appropriate, a boost ptr_container of some sort.
Further you might want to think if you need to spend one more iteration considering your design to provide an interface that doesn't require doing a dynamic_cast to get the original type back out again.
Is it possible to store a bunch of objects by their base class in say
an std::list without pointers.
This sentence seems to be contrdicted in C++ point of view IMO. Because STL container can only hold same type of object, if you put derived object into a base type container, it got sliced.
So the apparent normal solution is to use container to hold base type pointers like you did(u could use boost/std smart pointer for memory management)
If you really want to store different objects in one STL container, you may want to consider use boost::any.
In my new project I wish to (mostly for to see how it will work out) completely ban raw pointers from my code.
My first approach was to let all classes inherit from this simple class:
template
class Base
{
public:
typedef std::shared_ptr ptr;
};
And simple use class::ptr wherever I need a pointer.
This approach seemed suitable until I realized sometimes my objects wish to pass the 'this' pointer to other objects. Letting my objects just wrap it inside a shared_ptr won't do since then there could be two owners for the same pointer. I assume this is bad.
My next idea was to change the 'Base' class to implement reference counting itself, thus every instance of classes that inherits from 'Base' can only have one count.
Is this a good solution, are there any better and can boost and/or stl already solve this problem for me?
You may want to take a look at enable_shared_from_this.
On another note, when using shared_ptr, you need to be aware of the possibility of circular references. To avoid this, you can use weak_ptr. This means you will need some way to distinguish between the two of them, so simply having a typedef class::ptr may not suffice.
I'd like to manage a bunch of objects of classes derived from a shared interface class in a common container.
To illustrate the problem, let's say I'm building a game which will contain different actors. Let's call the interface IActor and derive Enemy and Civilian from it.
Now, the idea is to have my game main loop be able to do this:
// somewhere during init
std::vector<IActor> ActorList;
Enemy EvilGuy;
Civilian CoolGuy;
ActorList.push_back(EvilGuy);
ActorList.push_back(CoolGuy);
and
// main loop
while(!done) {
BOOST_FOREACH(IActor CurrentActor, ActorList) {
CurrentActor.Update();
CurrentActor.Draw();
}
}
... or something along those lines. This example obviously won't work but that is pretty much the reason I'm asking here.
I'd like to know: What would be the best, safest, highest-level way to manage those objects in a common heterogeneous container? I know about a variety of approaches (Boost::Any, void*, handler class with boost::shared_ptr, Boost.Pointer Container, dynamic_cast) but I can't decide which would be the way to go here.
Also I'd like to emphasize that I want to stay away as far as possible from manual memory management or nested pointers.
Help much appreciated :).
To solve the problem which you have mentioned, although you are going in right direction, but you are doing it the wrong way. This is what you would need to do
Define a base class (which you are already doing) with virtual functions which would be overridden by derived classes Enemy and Civilian in your case.
You need to choose a proper container with will store your object. You have taken a std::vector<IActor> which is not a good choice because
Firstly when you are adding objects to the vector it is leading to object slicing. This means that only the IActor part of Enemy or Civilian is being stored instead of the whole object.
Secondly you need to call functions depending on the type of the object (virtual functions), which can only happen if you use pointers.
Both of the reason above point to the fact that you need to use a container which can contain pointers, something like std::vector<IActor*> . But a better choice would be to use container of smart pointers which will save you from memory management headaches. You can use any of the smart pointers depending upon your need (but not auto_ptr)
This is what your code would look like
// somewhere during init
std::vector<some_smart_ptr<IActor> > ActorList;
ActorList.push_back(some_smart_ptr(new Enemy()));
ActorList.push_back(some_smart_ptr(new Civilian()));
and
// main loop
while(!done)
{
BOOST_FOREACH(some_smart_ptr<IActor> CurrentActor, ActorList)
{
CurrentActor->Update();
CurrentActor->Draw();
}
}
Which is pretty much similar to your original code except for smart pointers part
My instant reaction is that you should store smart pointers in the container, and make sure the base class defines enough (pure) virtual methods that you never need to dynamic_cast back to the derived class.
As you have guessed you need to store the objects as pointers.
I prefer to use the boost pointer containers (rather than a normal container of smart pointers).
The reason for this is the boost ptr container access the objects as if they were objects (returning references) rather than pointers. This makes it easier to use standard functors and algorithms on the containers.
The disadvantage of smart pointers is that you are sharing ownership.
This is not what you really want. You want ownership to be in a single place (in this case the container).
boost::ptr_vector<IActor> ActorList;
ActorList.push_back(new Enemy());
ActorList.push_back(new Civilian());
and
std::for_each(ActorList.begin(),
ActorList.end(),
std::mem_fun_ref(&IActor::updateDraw));
If you want the container to exclusively own the elements in it, use a Boost pointer container: they're designed for that job. Otherwise, use a container of shared_ptr<IActor> (and of course use them properly, meaning that everyone who needs to share ownership uses shared_ptr).
In both cases, make sure that the destructor of IActor is virtual.
void* requires you to do manual memory management, so that's out. Boost.Any is overkill when the types are related by inheritance - standard polymorphism does the job.
Whether you need dynamic_cast or not is an orthogonal issue - if the users of the container only need the IActor interface, and you either (a) make all the functions of the interface virtual, or else (b) use the non-virtual interface idiom, then you don't need dynamic_cast. If the users of the container know that some of the IActor objects are "really" civilians, and want to make use of things which are in the Civilian interface but not IActor, then you will need casts (or a redesign).