【问题标题】:C++: Strange vector behaviorC++:奇怪的向量行为
【发布时间】:2013-05-16 18:49:15
【问题描述】:

在为我的作业编写代码时,我遇到了一种奇怪的行为。代码很大,虽然没必要,我就不贴了。

问题是当我试图从向量中删除一个对象时,我遇到了分段错误。在尝试自己调试时,我发现了这一点:

如果我使用以下 sn-p 执行我的代码,我的向量为空,然后第二行出现分段错误(因为向量为空)。

cout << this->adjacencyList.empty() << endl; // yeah, I'm working with graph
cout << *(this->adjacencyList[0]) << endl; // list has pointers

但是,当我删除第二行时,它显示向量不为空,然后继续。 空向量的守卫不能保持它,分段错误来了。

你对这种行为有什么想法吗?如果这一点仍然含糊不清,我可以发布我的完整代码作为编辑。

提前致谢。

编辑:

对于那些要求“多一点”的人。

void Node :: removeEdge (string destination) // removes an edge; edge is a class that contains a pointer to another node and its weight
{
    bool deleted = false;
    cout << *this << endl; // output stream operator is overloaded for node class and is working properly - shows it's label and edges - no error for an edge
    cout << this->adjacencyList.empty() << endl;
    // cout << *(this->adjacencyList[0]) << endl; // output stream operator is overloaded for edge class - error for an edge
    if (!this->adjacencyList.empty())
    {
        for (vector <Edge *> :: iterator itr = this->adjacencyList.begin(); itr != this->adjacencyList.end(); ++itr)
        {
            if (((*itr)->getAdjacent())->getLabel() == destination) // segfault here
            {
                Edge *temp = *itr;
                this->adjacencyList.erase (itr);
                delete temp;
                deleted = true;
            }
        }
    }
    if (!deleted)
        throw EDGE_DOES_NOT_EXIST; // one of exceptions declared in enum somewhere in my code
}

第二次编辑:

注意:我无法更改标题(它们是由助手提供的),所以不要要求我更改。

如果您对完整代码感兴趣,可以在这里找到

http://pastebin.com/iCYF6hdP - Exceptions.h - 所有异常

http://pastebin.com/1fcgHGDa - Edge.h - 边缘类声明

http://pastebin.com/C2DD6e3D - Edge.cpp - 边缘类实现

http://pastebin.com/ZNqQ1iHE - Node.h - 节点类声明

http://pastebin.com/kaVtZ3SH - Node.cpp - 节点类实现

http://pastebin.com/A7Fwsi4m - Network.h - 图类声明

http://pastebin.com/02LX0rjw - Network.cpp - 图类实现

http://pastebin.com/MRMn0Scz - main.cpp - 示例主目录

【问题讨论】:

  • adjacencyList的声明是什么?
  • adjacencyList() 是一个函数,而不是一个向量。只要没有人知道这个函数实际上对你的向量做了什么,就很难说......
  • 你能告诉我们“多一点”吗?
  • 我已经删除了我的答案,因为我错过了关于empty() 在第一种情况下返回true 的部分。当更改随机代码具有看似无关的效果时,通常会涉及未定义的行为或内存损坏。
  • 存在段错误的行中有两个指针引用。其中一个必须可能无效

标签: c++ vector segmentation-fault


【解决方案1】:

我猜,存储在向量第一个元素中的指针是无效的(可能是NULL?)。

所以段错误不会出现在 this-&gt;adjacencyList[0] 中,而是出现在 *(some_invalid_pointer) 中。

试试

Edge* firstEdge = this->adjacencyList[0];
cout << *firstEdge << endl;

验证这一点。

编辑

如果段错误发生在第一条语句(赋值)中,这意味着this 无效或者您以某种方式设法破坏了属于vector 内部的内存。为了验证这一点,我们必须查看所有处理您的adjacencyList 的代码(我不确定 SO 人是否有时间完成这项任务......)

注意

我在removeEdge 中发现了一个与您的问题没有直接关系的错误。在循环中,您使用vector::erase 删除当前元素。这使当前迭代器之外的所有迭代器无效,因此理论上循环的其余部分是臭名昭著的“未定义行为”(TM)。在这种特定情况下(假设是“普通”标准库),这不会导致段错误,但您可能会错过一些元素:

如果删除当前元素,当前迭代器(通常只是一个指针)将指向下一个元素。然后,循环增量会将其移动到该元素之后的元素,导致一个元素未被检查。

如果您的代码在其他地方有类似的错误,这很可能会导致内存损坏。

提示

如果您使用的是 Microsoft C++,则可以启用检查迭代器(请参阅here)。这些可能能够在您的代码中发现此类错误。

第二次编辑(响应代码)

Node::operator+ 中有严重错误。

Node &operator+ (Node &l, Node &r) // merges two nodes - for network merging
{
Node newNode (l.label);
    // Doing something
return newNode;
}

这意味着,您正在返回 对局部变量的引用永远不要这样做 :) ...

请注意,由于您使用的是指针向量,它们在析构函数中单独管理并释放,因此您不能简单地将签名更改为Node operator+(...:在这种情况下,将调用标准的复制构造函数,它将简单地将所有指针复制到结果对象。然后,将调用本地对象的析构函数,这将使所有指针无效。

要解决这个问题,您应该在Node 上实现一个复制构造函数,它会生成邻接列表中所有边的真实副本。

或者,您可以对列表使用智能指针(auto_ptrunique_ptrshared_ptr)。

或者您将合并函数更改为 Node::mergeFrom(Node&amp; node2) 之类的东西,而不是重载 +operator。

关于最初的问题,您可以很容易地使用当前代码处理无效的 Node 实例(因此 *this-Pointer 在 removeEdge 中无效)

【讨论】:

  • 给出了分配的段错误
  • 但是现在边缘根本没有被删除
  • 是的,我知道他们,如果我能改变标题,我肯定会改变一切,但不幸的是我不能,我猜助手的手不是从正确的地方长出来的
  • 阅读stackoverflow.com/questions/2337213/…,了解在operator+ 中返回引用。把它展示给你的助手。从加法运算符返回引用通常是个坏主意...
猜你喜欢
  • 2014-04-08
  • 2016-06-28
  • 2013-03-31
  • 1970-01-01
  • 2015-08-12
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多