我寫一個工人階級的模板,這也可能只是一個愚蠢的問題,但如果我有一個模板結構(鏈表)到可能持有對象的指針,然後我怎麼知道他們正在被刪除,還是他們在哪裏指針?確定模板類型是動態
例如:LinkedList的將在第2種方式使用在此程序
一個指針指向類的東西的物體被放置在節點內的鏈表
枚舉被放置在節點內的內部內一個linkedList
我知道節點正在被刪除,但我怎麼知道節點中的東西是一個指針,以便它可以被刪除,而不僅僅是一個空引用對象?
我寫一個工人階級的模板,這也可能只是一個愚蠢的問題,但如果我有一個模板結構(鏈表)到可能持有對象的指針,然後我怎麼知道他們正在被刪除,還是他們在哪裏指針?確定模板類型是動態
例如:LinkedList的將在第2種方式使用在此程序
一個指針指向類的東西的物體被放置在節點內的鏈表
枚舉被放置在節點內的內部內一個linkedList
我知道節點正在被刪除,但我怎麼知道節點中的東西是一個指針,以便它可以被刪除,而不僅僅是一個空引用對象?
您可以專注基於對象的類型的節點,併爲指針專業化,創建節點型,妥善分配,並刪除節點管理的指針析構函數。
例如:
//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
模板專業化是最好的答案,並且將工作做好,只要你不混合類型的節點。但是,如果你想混合鏈接節點的類型,讓我告訴你如何去做。首先,沒有簡單的模板解決方案。由於嚴格的類型限制,您必須一起鍵入您的鏈接節點。
甲相當普遍的解決方案是構建變體類(其可以容納具有變化類型的一個值,並且總是知道哪一個)。例如,Qt有一個QVariant類。 Boost有boost::any。
這是一個完整的示例實現,它使用可以容納任何類型的自定義變體類。我可以處理你建議的對象指針和枚舉,但可以擴展來保存更多。
這將打印「刪除目標文件」一旦一個例子:
#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();
}
};
因爲調用一次當鏈表的析構函數被調用elementObj的破壞方法,輸出的「刪除目標文件」中出現一次。同樣,由於您對刪除/所有權非常具體,因此此示例具有銷燬方法/接口。它將在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類型將無法工作。這將不兼容。
腳註: 類型約束如何防止一個簡單的解決方案嗎?想象一下,鏈接節點的「下一個」指針類型不僅僅是裸模板名稱,它是一個快捷方式,但實際上還包括模板參數 - 最終作爲編譯器用來判斷類型兼容性的類型符號。
您是否想製作不同類型的鏈接列表? – Xeo 2012-03-07 19:26:18
爲了確保我正確理解這一點,你想有一個LinkedList3210,然後能夠推動Blah *進入它並讓LinkedList自動銷燬並釋放鏈表的內容指向的所有對象?這似乎是班上不應該做的事情。如果你想保持一個對象存活,但是你已經將它推入列表並且該列表已被刪除,該怎麼辦?也許你正在尋找某種智能指針? (像Boost智能指針。) – Corbin 2012-03-07 19:28:16
@Xeo是的,但我的其中一種類型將枚舉(靜態),另一種類型將指向事物(動態)。結構已經存在,我正在努力,雖然現在將它轉換爲模板 – gardian06 2012-03-07 19:28:49