1

This is my scenario (for brevity I have taken out the permissions and instance variables, only the relevant methods):

template <typename ItemType>
class LinkedList
{
    class Item
    {
        Item(ItemType theObj, bool freeObj);
        ~Item();
    };

    void add(LinkedList<ItemType>::Item item);
};

template <typename ItemType>
LinkedList<ItemType>::Item::~Item()
{
    if(freeObj) {
        delete obj;
    }
}

In my code I used it like this:

// works great
LinkedList<MyObject*> mylist;
mylist.add(LinkedList<MyObject*>::Item(new MyObject(), false));

// won't compile because you cannot use delete operator on a non-pointer
LinkedList<MyObject> mylist;
mylist.add(LinkedList<MyObject>::Item(MyObject(), false));

Let's put aside the fact that LinkedList<>::Item should not free the actual object. This is more of an understanding templates question. I need to specify an explicit template for the Item destructor to handle when ItemType is a pointer and when its not.

Is this possible? What are some potential design/leak pit falls? Thanks.

Elliot Chance
  • 5,526
  • 10
  • 49
  • 80
  • `for brevity I have taken out the permissions` And by doing so you have totally broken the example. Where is your [testcase](http://kera.name/articles/2013/10/nobody-writes-testcases-any-more/), pal? – Lightness Races in Orbit Nov 06 '13 at 03:18

2 Answers2

0

You're probably looking for partial template specialization. What you can do is special case for a ItemType * and have your internal Item's destructor not perform the delete. Something along the lines of:

// General form
template <typename ItemType>
class LinkedList
{
public:
    class Item
    {
        Item(ItemType theObj, bool);
        ~Item() {}
    };

    void add(Item item);
};

// specialize for when ItemType is a pointer
template <typename ItemType>
class LinkedList <ItemType *>
{
public:
    class Item
    {
        Item(ItemType *theObj, bool freeObj);
        ~Item() 
        {
          if(freeObj) delete obj;
        }
    };

    void add(Item item);
};

Edit: Responding to your first comment. I think you may be able to accomplish this without too much code duplication even without relying on SFINAE. What I would do is move freeObj as a non-type parameter to LinkedList and keep class Item private. The wrapper is just an implementation detail and client code has no business knowing about it. Here's what the proposed alternative would look like:

template <typename ItemType, bool freeObj = false>
class LinkedList
{
    template <typename T> 
    class Item
    {
        T obj;
    public:
        Item(T theObj);
        ~Item();
    };
    template <typename T>
    class Item <T *>
    {
        T *obj;
    public:
        Item(T *theObj);
        ~Item() { if(freeObj) delete obj; }
    };

public:
    void add(ItemType) {}
};

Here's a simple demo example.

Community
  • 1
  • 1
greatwolf
  • 20,287
  • 13
  • 71
  • 105
  • Thanks! ... I have a lot of methods for LinkedList as well and the subclasses SynchronizedLinkedList / UnsynchronizedLinkedList. Is it possible to move all the methods from LinkedList into LinkedListAbstract and extend that so that I only have to implement the Item destructors, or do I have to basically have to have two whole copies of LinkedList which almost exactly the template code duplicated? – Elliot Chance Nov 06 '13 at 02:32
  • There's a way to specialize the `Item` class to use one implementation if it's a pointer and a different implementation for non-pointers probably using SFINAE technique like [`std::enable_if`](http://www.cplusplus.com/reference/type_traits/enable_if/) – greatwolf Nov 06 '13 at 02:40
0

The answer is: don't. When I have a container of pointers, I do not expect the container to own the pointees. In fact, nobody expects this, and the standard library containers do not work this way.

If nothing else, you're making a big mess of memory management by making illogical assumptions about how each element's pointee was allocated and about who owns them.

The list did not new these pointees, so it shall not delete them. Simples!

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055