C++中使用向量出现了分段错误

3

我遇到了一个由以下代码行引起的分段错误问题:

heapVec[currentsize] = *(new Node(d));

我在这里做错了什么?

#include <vector>
using namespace std;

class Node {
private:
    int data;
public:
    Node(int);
    // ~Node();
};

class Heap {
private:
    vector<Node> heapVec;
    int currentsize;
public:
    Heap();
    // ~Heap();
    void insert(int);
    void extractMin();
    void reduceKey();
};

Node::Node(int d) {
    data = d;
}

void Heap::insert(int d) {
    heapVec[currentsize] = *(new Node(d));
    currentsize++;
}

Heap::Heap() {
    // this is the default constructor
    currentsize = 0;
}

int main() {
    Heap *h = new Heap;
    h->insert(10);
}

代码*(new Node(d))是完全错误的。它分配了类Node的对象,但忘记了指针。这是内存泄漏的定义。您必须将vector<Node> heapVec;更改为vector<Node*> heapVec;或使用类似于boost::ptr_vector<Node> heapVec;的东西。 - Arpegius
不要使用vector<Node*>。你很可能会遇到内存泄漏问题,因为你必须手动删除每个向量成员。 只需按照下面Dani所说的做,就可以了。 - Ben
请提供一个完整的、最小化的程序,以演示您遇到的问题。请参考 http://sscce.org 了解其有价值的原因。 - Robᵩ
2
另外,currentsize 是多余的。当您想要知道当前大小时,只需使用 heapVec.size() 即可。 - Robᵩ
@Rob:我真的不认为这是最简化的...它可以被缩减到3行左右。 - Daniel
@Dani,你说得对。但它比我们在SO上看到的那么多程序更接近最小化。 - Robᵩ
6个回答

12

当使用下标运算符写出向量的边界时,向量不会自动增长。要在向量末尾插入元素(增加其大小),请使用以下代码:

heapVec.push_back(Node(d));

同时也不要使用*(new Node(d)),它不会导致段错误,但这是一种内存泄漏的方式。


3

在通过索引访问向量之前,您需要为其分配空间。

 heapVec[currentsize] = *(new Node(d));

使用heapVec.resize(currentsize + 1)即可。这将确保heapVec至少具有currentsize + 1个元素,您可以访问currentsize。

避免此问题的一种方法是修改您的函数。因为您只是在向向量末尾添加元素。

void Heap::insert(int d) {
    heapVec.push_back( Node(d) );
    currentsize++;
}

请注意您拥有的是 vector<Node> 而不是 vector<Node*>,因此您不需要使用 new 关键字。

此外,向量具有 size() 方法,因此您不需要通过拥有自己的 currentSize 来复制它。


我明白你的意思,但这给了我以下错误信息:minheap.cpp:33: 错误:没有与‘Node::Node()’匹配的函数 minheap.cpp:28: 注意:候选函数是:Node::Node(int) minheap.cpp:8: 注意: Node::Node(const Node&) - user316602
你需要为放入std::vector中的任何东西提供一个默认构造函数。 - Mike DeSimone
@DanielO'Connor:当然,你需要为Node定义一个默认构造函数。如果没有默认构造函数,你就不能使用std::vector的Nodes。 - Arne

1

首先,您正在向矢量范围之外写入内容,这会导致分段错误。您需要将矢量的大小调整为足够大,以包含它,或者使用push_back()自动调整大小。

其次,您存在内存泄漏——您没有充分的理由使用new创建一个Node,然后将其复制到矢量中,然后丢失指针,因此永远不会删除第一个对象。

您需要的是

heapVec.push_back(Node(d));

或者在C++11中

heapVec.emplace_back(d);

我还会去掉你多余的currentsize变量,改用heapVec.size()。此外,在main()中不要使用new来创建本地堆;通常情况下,除非你确实需要,否则不要使用new,当你使用时,一定要使用智能指针或非常小心编写的代码来确保对象被删除。

0

我非常确定你之所以出现这个错误,是因为你试图超出向量的边界。在向量操作中不要使用数组语法(虽然允许),在Heap::insert()中使用heapVec.push_back()

另一件事是,如果Node类型只包含int成员,那么你不应该费心使用它。为什么不直接使用vector<int>呢?

你可以进一步简化你的类。当你已经有了std::vector时,你的currentsize成员是多余的(不必要的),因为vector::size()将告诉你它的当前大小。


0
这里我做错了什么?
有几个不同的问题,包括导致崩溃的错误。请看下面我的评论。
#include <vector>

// Never, ever, say "using namespace std;" even if (especially if) your textbook says to.
// using namespace std;
using std::vector;

class Node {
private:
    int data;
public:
    // Prefer to define small functions in-class so that they are automatically inline
    // Prefer initialization list to assignment. This is mostly style in your case, but
    // does matter in more complex cases.
    Node(int d) : data(d) {}
    // ~Node();
};

class Heap {
private:
    vector<Node> heapVec;
    // int currentsize;  "currentsize" is redundant, and thus error-prone.
    // heapVec always knows what size it is, so just ask it whenever you need to know.
public:
    // In this trivial example, with currentsize gone, you don't need any constructor.
    // Heap();
    // ~Heap();
    void insert(int);
    void extractMin();
    void reduceKey();
};

void Heap::insert(int d) {
    // This is your crash bug -- std::vector::operator[] doesn't automatically extend
    // the size of the vector (unlike, say, std::map::operator[], which does).
    // Also, your use of "new" here is unconventional, and buggy. You have a memory leak.
    // It is possible to write perfectly useful C++ programs while never invoking "new"
    // directly.
    // heapVec[currentsize] = *(new Node(d));
    // currentsize++;

    // Instead, use std::vector::push_back() or std::vector::insert(), *and* don't call
    // new.
    heapVec.push_back(Node(d));
}


int main() {
    // In this example (and, I bet, in your real-world program), you don't need "new"
    Heap h;
    h.insert(10);
}

-1

你犯了两个错误:第一个问题是你在heapVec的特定位置插入元素时没有为其分配内存。解决方法是在Heap构造函数中调用heapVec.reserve(...),或者在insert中调用heapVec.push_back(Node(d))

另一个问题是,在向向量中插入节点时,你会分配新的节点并获取其内容,这将创建一个存储在向量中的副本。但你没有存储实际分配的指针,这意味着你有一个内存泄漏。在这种情况下,你不应该进行分配。


2
reserve() 没有帮助,除了用更微妙的未定义行为替换分段错误之外 - 访问数组末尾之外的对象仍然是非法的。在访问它们之前,您需要使用 resize() 进行调整大小。 - Mike Seymour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接