I'm really having a hard time to determine why this program is segfaulting. I am using a std::list containing objects pointer in object Park
. Everything seems to work fine but when I use the iterator of the list and try to call some object method, it segfaults.
I discovered that if I modify the type of the std:list<Felid*>
to std:list<Felid*>*
, there is no more segfault.I would like to understand why this is working ?
I compile this with 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
}
The problem is with the std::list<Felid*> getFelids()
method. It's returning the list by value, so every time you call it you get a new copy of the list. You should return a reference with std::list<Felid*>&
The segfault is because your iterator's begin()
and end()
are from different lists (because you're making a copy each time), so the iterator never reaches the end()
of the first list and keeps going through random memory.
Also, the list you're iterating through was just a temporary, so it's gone by the time you try to use the iterator.