Search code examples
c++polymorphismresource-management

Program design concerning polymorphism & resource management


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.


Solution

  • 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.