【问题标题】:C++ custom template LinkedList crashes adding std::stringC++ 自定义模板 LinkedList 添加 std::string 崩溃
【发布时间】:2013-08-23 00:05:50
【问题描述】:

出于学术目的,我正在尝试开发一个小的“文字冒险游戏”。我必须自己实现所有数据结构。现在,我在实现通用(模板)LinkedList 时遇到了一些问题。

具体来说,这个数据结构适用于所有东西(原始数据类型和自定义对象),但字符串! (标准库字符串)。

当我尝试将字符串添加到列表时,应用程序崩溃并出现以下错误(在控制台中):

"在抛出 'std::logic_error' 的实例后调用终止 what(): basic_string::_S_constructor null 无效"

列表实现为“双链表”,使用头节点作为首尾节点

这里是代码(“抽象”列表界面):

#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_ */

建议?

【问题讨论】:

  • 也可以手写你的std::string
  • 您必须实现自己的数据结构,但允许使用std::string?如果可以使用std::string,为什么不能使用std::list
  • 考虑在方法调用中使用对包含对象的引用。您正在制作大量额外的字符串副本。这并没有解决您的问题,因此它只是一个评论。
  • 只是一个观察,在析构函数上你正在删除一个没有动态分配的对象。
  • 您能否准确地向我们展示您是如何使用这些类的,并告诉我们当您尝试添加字符串时它会中断哪一行?虽然我同意在未动态分配的变量上调用 delete 是一个问题,但如果您在将字符串添加到模板列表时程序崩溃,那么这不是您看到的错误的原因.

标签: c++ string list nodes


【解决方案1】:

你的部分问题在这里:

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 之外很明显。

【讨论】:

  • 你能用一段代码描述你的答案吗?顺便说一句,奇怪的是它不仅仅适用于字符串:当我实例化一个自定义对象列表时,我没有收到任何错误。使用 std::string 我在 "List list = new LinkedList()": "warning: FTH: (4344): *** 应用于当前进程的容错堆 shim 之后收到以下控制台警告。这通常是由于以前的崩溃造成的。*** 警告:未找到类“LinkedList<:string>”的 RTTI 符号警告:未找到类“LinkedList<:string>”的 RTTI 符号”
  • 您得到的错误是另一个不相关的问题,user2093113 在下面描述。一旦您解决了该问题,您将在所有类型中看到此错误。
【解决方案2】:

在你的程序中某处你正在这样做:

std::string s(nullptr);

使用空指针调用std::string 的构造函数会导致它抛出std::logic_error 异常。

来自标准:

§ 21.4.2

basic_string(const charT* s, size_type n, const Allocator& a = Allocator());

要求:s 不能是空指针并且 n

【讨论】:

    【解决方案3】:

    似乎无法将 std::string 作为模板参数传递...

    Strings as Template Arguments

    现在我使用“旧” - char const* - 来实现预期结果,即使我现在必须实现我个人的“utils”方法来处理这些指针......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多