我正在编写一个工作类的模板,这可能只是一个愚蠢的问题,但如果我有一个模板结构(链表)来保存可能指向对象的指针,那么我怎么知道它们被删除了,或者说他们在哪里指针?
例如:linkedList将在此程序中以2种方式使用
指向Thing类对象的指针放在linkedList
内的节点内枚举被放置在linkedList
内的节点内我知道节点正在删除,但我怎么知道节点中的东西是一个指针,以便它也可以被删除,而不仅仅是一个空引用对象?
答案 0 :(得分:4)
您可以根据对象的类型对节点进行专门化,对于指针特化,可以为节点类型创建一个析构函数,以正确分配和删除节点管理的指针。
例如:
//general node type for non-pointer types
template<typename T>
struct linked_list_node
{
T data;
linked_list_node<T>* next;
linked_list_node(const T& d): data(d), next(NULL) {}
~linked_list_node() {}
};
//specialized version for pointer types
template<typename T>
struct linked_list_node<T*>
{
typedef void (*deleter)(T*);
T* data;
linked_list_node<T>* next;
deleter d_func; //custom function for reclaiming pointer-type
linked_list_node(const T& d): data(new T(d)), next(NULL), d_func(NULL) {}
linked_list_node(const T& d, deleter func): data(new T(d)),
next(NULL), d_func(func) {}
~linked_list_node()
{
if(d_func)
d_func(data); //execute custom function for reclaiming pointer-type
else
delete data;
}
};
然后,您可以在创建linked_list_node
类型的实例时通过传递正确的模板参数来实例化不同的版本。例如,
linked_list_node<MyPtr*> node(FooPtr); //creates the specialized ptr version
linked_list_node<MyEnum> node(FooEnum); //creates a non-ptr version of the node
答案 1 :(得分:1)
模板专业化是最好的答案,只要您不混合节点类型,它就会很好用。但是,如果要混合链接节点的类型,请告诉我如何操作。首先,没有直接的模板解决方案。由于严格的类型约束,您必须将链接节点类型转换为一起。
一个非常常见的解决方案是构造一个变体类(可以使用变量类型保存一个值,并始终知道哪个值)。例如,Qt有一个QVariant类。 Boost有boost::any。
这是一个完整的示例实现,它使用可以容纳任何类型的自定义变体类。我可以处理你建议的对象指针和枚举,但可以扩展到更多。
一次打印“删除obj”的例子:
#include <iostream>
int
main( int argc, char **argv )
{
LinkedList<VariantExample> elementObj( new ExampleObj );
LinkedList<VariantExample> elementEnum( enumOne );
elementEnum.setNext( elementObj );
}
// VariantExample class. Have a look at [QVariant][4] to see how a fairly
// complete interface could look like.
struct ExampleObj
{
};
enum ExampleEnum
{
enumOne,
enumTwo
};
struct VariantExample
{
ExampleObj* obj; // or better boost::shared_ptr<ExampleObj> obj
ExampleEnum en;
bool is_obj;
bool is_enum;
VariantExample() : obj(0), is_obj(false), is_enum(false) {}
// implicit conversion constructors
VariantExample( ExampleObj* obj_ ) : is_obj(true), is_enum(false)
{ obj = obj_;
}
VariantExample( ExampleEnum en_ ) : obj(0), is_obj(false), is_enum(true)
{ en = en_;
}
// Not needed when using boost::shared_ptr above
void
destroy()
{
if( is_obj && obj )
{
std::cout << "delete obj" << std::endl;
delete obj;
}
}
};
// The linked list template class which handles variant classes with a destroy()
// method (see VariantExample).
template
<
typename _type_ = VariantExample
>
struct LinkedList
{
LinkedList* m_next;
_type_ m_variant;
explicit
LinkedList( _type_ variant_ ) : m_next(0), m_variant( variant_ ){ }
void
setNext( LinkedList& next_ ){ m_next = &next_; }
// Not needed when using boost::shared_ptr above
~LinkedList()
{
m_variant.destroy();
}
};
因为在调用LinkedList的析构函数时elementObj的destroy方法调用了一次,所以输出“delete obj”只出现一次。同样,由于您对删除/所有权非常具体,因此该示例具有destroy方法/接口。它将在LinkedList类的析构函数中显式调用。可以用ie实现更好的所有权模型。 boost::shared_ptr。然后你不需要手动销毁它。顺便说一下,阅读conversion constructors会很有帮助。
// the first parameter becomes boost::shared_ptr<ExampleObj>( new ExampleObj ) )
// and is deleted when LinkedList is destroyed. See code comments above.
LinkedList<> elementObj( new ExampleObj );
最后请注意,您必须拥有一个变体类来保存可能出现在LinkedList链中的所有类型。最后,由于“下一个”指针类型,两个不同的LinkedList Variant类型不起作用;这是不兼容的。
脚注: 类型约束如何阻止简单的解决方案?想象一下,您的链接节点“下一个”指针类型不仅仅是裸模板名称,它是一个快捷方式,但实际上是合格的,包括模板参数 - 最终作为编译器用来判断类型复杂性的类型符号。