2013-08-20 27 views
0

爲了學術目的,我試圖開發一個「文本冒險遊戲」。我必須自己實現所有的數據結構。現在,我在實現通用(模板)LinkedList時遇到了一些問題。C++自定義模板LinkedList崩潰添加std :: string

具體來說,這個數據結構適用於一切(原始數據類型和自定義對象)但是字符串! (標準庫字符串)。

當我嘗試將字符串添加到列表中,應用程序崩潰,出現以下錯誤(控制檯):

「扔‘的std :: logic_error’ 的一個實例後終止叫什麼():basic_string的:: _ S_constructor空無效」

列表被實現爲‘雙鏈表’利用頭節點作爲第一最後一個節點

下面的代碼(‘摘要’List接口):

#ifndef LIST_H_ 
#define LIST_H_ 

template <class T> 
class List 
{ 
public: 
virtual ~List() {} 
virtual T get(int position) = 0; 
virtual List* add(T item) = 0; 
virtual List* insert(T item, int position) = 0; 
virtual List* remove(int position) = 0; 
virtual int size() const = 0; 
virtual bool isEmpty() const = 0; 

protected: 

private: 

}; 

#endif /* LIST_H_ */ 

這是LinkedList的實現( 「節點」 類):

#include "List.h" 
#include <stdlib.h> 

#ifndef LINKEDLIST_H_ 
#define LINKEDLIST_H_ 

template <class T> 
class ListNode 
{ 
public: 
ListNode(T item) 
{ 
    mItem = item; 
    mNext = NULL; 
    mPrev = NULL; 
} 

ListNode(T item, ListNode<T>* next, ListNode<T>* prev) 
{ 
    mItem = item; 
    mNext = next; 
    mPrev = prev; 
} 


~ListNode() 
{ 
    delete &mItem; 
} 


T getItem() 
{ 
    return mItem; 
} 


ListNode<T>* getNext() 
{ 
    return mNext; 
} 


ListNode<T>* getPrev() 
{ 
    return mPrev; 
} 


void setItem(T item) 
{ 
    mItem = item; 
} 


void setNext(ListNode<T>* next) 
{ 
    mNext = next; 
} 


void setPrev(ListNode<T>* prev) 
{ 
    mPrev = prev; 
} 

protected: 
private: 
T mItem; 
ListNode<T> *mNext, *mPrev; 
}; 

LinkedList類:

template <class K> 
class LinkedList : public List<K> 
{ 
public: 
LinkedList() 
{ 
    mSize = 0; 
    mFirstNode = NULL; 
} 

~LinkedList() 
{ 
    // implementazione distruttore tramite ciclo sui nodi 
} 

K get(int position) 
{ 
    K item = NULL; 

    ListNode<K>* targetNode = getNodeAtPosition(position); 
    if (targetNode != NULL) item = targetNode->getItem(); 

    return item; 
} 

List<K>* add(K item) 
{ 
    if (mFirstNode == NULL) 
    { 
     mFirstNode = new ListNode<K>(item); 
     mFirstNode->setNext(mFirstNode); 
     mFirstNode->setPrev(mFirstNode); 
    } 
    else 
    { 
     ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev()); 
     mFirstNode->getPrev()->setNext(newNode); 
     mFirstNode->setPrev(newNode); 
    } 

    mSize++; 
    return this; 
} 

List<K>* insert(K item, int position) 
{ 
    ListNode<K>* targetNode = getNodeAtPosition(position); 

    if (targetNode != NULL) 
    { 
     ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode); 
     targetNode->setItem(item); 
     targetNode->setNext(newNode); 

     mSize++; 
    } 

    return this; 
} 

List<K>* remove(int position) 
{ 
    ListNode<K>* targetNode = getNodeAtPosition(position); 
    if (targetNode != NULL) 
    { 
     targetNode->setItem(targetNode->getNext()->getItem()); 
     targetNode->setNext(targetNode->getNext()->getNext()); 

     //delete targetNode->getNext(); 
     mSize--; 
    } 

    return this; 
} 

int size() const 
{ 
    return mSize; 
} 

bool isEmpty() const 
{ 
    return (mFirstNode == NULL) ? true : false; 
} 

protected: 
ListNode<K>* getNodeAtPosition(int position) 
{ 
    ListNode<K>* current = NULL; 

    if (mFirstNode != NULL && position < mSize) 
    { 
     current = mFirstNode; 

     for (int i = 0; i < position; i++) 
     { 
      current = current->getNext(); 
     } 
    } 

    return current; 
} 

private: 
    int mSize; 
    ListNode<K>* mFirstNode; 
}; 

#endif /* LINKEDLIST_H_ */ 

建議?

+0

也許還要手寫你的'std :: string'? – TemplateRex

+0

你必須實現你自己的數據結構,但是可以使用'std :: string'?如果你可以使用'std :: string',爲什麼你不能使用'std :: list'? –

+0

考慮在您的方法調用中使用對包含對象的引用。您正在製作大量額外的字符串副本。這不能解決你的問題,因此它只是一個評論。 –

回答

3

某處在你的計劃,你這樣做是:

std::string s(nullptr); 

調用std::string的空指針的構造導致它拋出一個異常std::logic_error

從標準:

§21.4.2

basic_string的(常量圖表* S,SIZE_TYPE N,const的分配器&一個=分配器());

要求:s不得爲空指針和n < npos。你的問題的

5

部分是在這裏:

ListNode(T item) 
{ 
    mItem = item; // for a std::string, this will be a class member, non-pointer 
    mNext = NULL; 
    mPrev = NULL; 
} 

ListNode(T item, ListNode<T>* next, ListNode<T>* prev) 
{ 
    mItem = item; // same here 
    mNext = next; 
    mPrev = prev; 
} 


~ListNode() 
{ 
    delete &mItem; // you are attempting to delete an item you never created 
} 

你要麼改變你的構造函數在堆上創建一個T*對象(隨後將在你的析構函數被刪除),或刪除delete線來自你的析構函數。順便說一下,這個問題將明顯不止std::string

+0

你能用一段代碼來描述你的答案嗎?順便說一下,奇怪的是它不能只用字符串工作:當我實例化一個自定義對象列表時,我不會收到任何錯誤。使用std :: string在「List list = new LinkedList ()」後面收到以下控制檯警告:「warning:FTH:(4344):***容錯堆填充應用於當前進程。以前崩潰*** 警告:找不到類RTTI符號「的LinkedList 」 警告:未找到類的LinkedList的「RTTI符號 」 – Imhotep

+0

你所得到的錯誤是另一個不相關的問題,即user2093113描述如下。這個錯誤是一旦你解決了這個問題,你會看到所有類型的錯誤。 –

0

看來這是不可能通過的std :: string作爲模板參數...

Strings as Template Arguments

現在我用一個「老」 - 字符常量* - 要達到預期的結果,即使我必須實現我個人的「utils」方法來處理這些指針......