这是我的场景(为简洁起见,我删除了权限和实例变量,仅删除了相关方法):
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;
}
}
在我的代码中,我像这样使用它:
// 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));
让我们抛开 LinkedList<>::Item 不应该释放实际对象的事实。这更像是一个理解模板的问题。我需要为 Item 析构函数指定一个显式模板,以便在 ItemType 是指针时处理,何时不是指针。
这可能吗?有哪些潜在的设计/泄漏坑掉落?谢谢。
您可能正在寻找部分模板专用化。您可以做的是ItemType *
的特殊情况,并让您的内部Item
的析构函数不执行删除。大致如下:
// 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);
};
编辑:回复您的第一条评论。我认为即使不依赖 SFINAE,您也可以在不重复太多代码的情况下完成此操作。我要做的是将freeObj
作为非类型参数移动到LinkedList
并保持class Item
私有。包装器只是一个实现细节,客户端代码不知道它。以下是提议的替代方案
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) {}
};
下面是一个简单的演示示例。
答案是:不要。当我有一个指针容器时,我不希望容器拥有尖点。事实上,没有人期望这一点,标准库容器也不是这样工作的。
如果不出意外,你正在通过对每个元素的点的分配方式以及谁拥有它们做出不合逻辑的假设,使内存管理变得一团糟。
该名单没有new
这些尖头,因此不应delete
它们。简单!