【问题标题】:Segmentation Fault when operating on retrieved vector对检索到的向量进行操作时出现分段错误
【发布时间】:2013-08-13 23:46:53
【问题描述】:

我对 C++ 有点陌生,我有一个很好奇的问题。有一段时间我遇到了分段错误,虽然我最终让它工作了,但我想知道为什么以前没有。这就是我所拥有的:

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
class A {
    private:
        int num;
    public:
        A(int i){this->num=i;}
        int getNum(){return this->num;}
};
class B {
    private:
        vector<A*> list;
    public:
        vector<A*> getList(){return this->list;}
        void addA(A* i){this->getList().push_back(i);}
        string as_a_string(){
            stringstream result;
            cout << "Flag1" <<endl; //only for debug, this prints
            for (vector<A*>::iterator x = this->getList().begin(); x != this->getList().end(); ++x) {
                cout << "Flag2" << endl; //only for debug, this prints
                A* w = *x;
                cout << "Flag3" << endl; //only for debug, this prints
                result << w->getNum() << " ";
                cout << "Flag4" << endl; //only for debug, this does not print
            }
            return result.str();
        }
};
int main() {
    A* a = new A(4);
    B* b = new B();
    b->addA(a);
    cout << b->as_a_string() << endl;
    return 0;
}

我通过用this-&gt;list 替换this-&gt;getList() 的每个实例解决了我的问题(有3 个;一个在B::addA(A*) 中,两个在B::as_a_string() 的for 循环定义中)。为什么使用成员本身而不是通过方法访问它会影响该程序的工作?

【问题讨论】:

  • getList() 按值返回。每次调用它都会得到B::list 的副本。
  • 我曾想过,但我不知道如何让它返回一个参考(我认为这是正确的术语,无论如何),这会让它按照我的想法行事它应该表现。我该如何正确地做到这一点?

标签: c++ class vector segmentation-fault


【解决方案1】:

问题在于您的B::getList() 按值返回列表,因此实际上返回的是B::list 的副本,而不是原始列表本身。

在你的循环中:

for (vector<A*>::iterator x = this->getList().begin();
     x != this->getList().end(); ++x)

您首先获取此临时列表的开始迭代器。每次检查条件时,您都在将其与结束迭代器进行比较,以实现 不同的临时列表对象。

解决这个问题的简单方法是让 B::getList() 通过引用返回列表:

vector<A*>& getList();

【讨论】:

    【解决方案2】:

    由于getList 正在返回list 的临时副本,因此当您尝试遍历它时,list 将再次消失。

    有几种不同的方法来处理这个问题:

    1. 只需使用list(无需使用this-&gt; - 它不是PHP、Python 或某些您总是必须通过this/self 指针引用成员的语言)。
    2. getList 返回对向量的引用。 (vector&lt;A*&gt;&amp; getList() { ... };)
    3. 使用局部变量作为副本

    但是,选项 3 对 addA 没有帮助,它要求您在原始列表上进行操作 - 就目前而言,您的 push_backlist 的临时副本进行操作,该临时副本会立即被销毁afterpush_back 返回 - 所以它实际上并没有向实际的 list 成员变量添加任何内容。

    就个人而言,我会将您的内部代码更改为直接使用list,并保持getList 返回一个副本,以便如果某些外部函数想要获取列表,它可以。

    编辑:您还通过不删除您在main 中创建的 A* 和 B* 对象来泄漏内存。

    【讨论】:

      【解决方案3】:

      您的代码:

      class B {
          private:
              vector<A*> list;
          public:
              vector<A*> getList(){return this->list;}
              void addA(A* i){this->getList().push_back(i);}
      

      正在临时调用 push_back(),因为 getList() 按值返回。调用 add() 后,成员变量列表不变。您可以更改 getList() 函数签名以返回如下引用:

      vector<A*>& getList(){return this->list;}
      

      老实说,您可能最好使用您用来避免问题的解决方案,因为提供一个返回对您的实现细节的引用的公共访问器是您通常希望避免的事情。

      【讨论】:

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