Program design concerning polymorphism & resource management

94 views Asked by At

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.

3

There are 3 answers

3
Kirill Kobelev On BEST ANSWER

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.

0
Drax On

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.

0
Blue moe On

I think smart pointer is best choice. And if you feel template is ugly, try the typedef