0

我真的很难确定为什么这个程序会出现段错误。我正在使用一个 std::list 包含 object 中的 objects 指针Park。一切似乎都很好,但是当我使用列表的迭代器并尝试调用一些对象方法时,它会出现段错误。

我发现如果我修改std:list<Felid*>to的类型std:list<Felid*>*,就没有更多的段错误了。我想了解为什么这是有效的?

我用 g++ 编译它:g++ -g -Wall -std=c++11 main.cpp

main.cpp

#include <iostream>
#include <list>

class Felid {
    public:
        void do_meow() {
            this->meow(); // <-- Segfault occurs, why ?
        }
    protected:
        virtual void meow() = 0;
};

class Park {
    public:
        std::list<Felid*> getFelids() {
            return this->felids;
        }

        void add_felid(Felid* f) {
            this->getFelids().push_back(f);
        }

        void listen_to_felids() {
            for (std::list<Felid*>::iterator it = this->getFelids().begin(); it != this->getFelids().end(); it++)
            {
                (*it)->do_meow(); // <-- will Segfault
            }
        }
    protected:
        std::list<Felid*> felids;
};



class Cat : public Felid {
    protected:
        void meow() { std::cout << "Meowing like a regular cat! meow!\n"; }
};

class Tiger : public Felid {
    protected:
        void meow() { std::cout << "Meowing like a tiger! MREOWWW!\n"; }
};



int main() {
    Park* p = new Park();

    Cat* cat = new Cat();
    Tiger* tiger = new Tiger();

    p->add_felid(cat);
    p->add_felid(tiger);

    p->listen_to_felids(); // <-- will Segfault
}
4

3 回答 3

1

std::list<Felid*> getFelids()

这将返回列表的副本。对它的任何更改都不会影响felids您的班级。将返回类型更改为std::list<Felid*>&

于 2014-03-29T22:57:04.810 回答
1

关键问题是您按以下值返回列表而不是按引用返回列表

    std::list<Felid*> getFelids() {
        return this->felids;
    }

此处 getFelids 不返回 std::list 的副本,并且将 felids 添加到该副本不会添加到原始类成员中。当您通过指针返回时,您正在修改原始类成员。

正确的方法是通过指针(std::list<>*)或引用(std::list<>&)返回

于 2014-03-29T22:59:28.093 回答
1

问题出在std::list<Felid*> getFelids()方法上。它按值返回列表,因此每次调用它时都会得到列表的新副本。您应该返回一个参考std::list<Felid*>&

段错误是因为您的迭代器begin()end()来自不同的列表(因为您每次都在制作副本),所以迭代器永远不会到达end()第一个列表的第一个并继续通过随机内存。

此外,您正在迭代的列表只是一个临时的,所以当您尝试使用迭代器时它已经消失了。

于 2014-03-29T23:01:31.723 回答