使用迭代器遍历std::list<Server>时触发Segmentation Fault问题
问题:遍历std::list时触发段错误
尝试用迭代器遍历std::list<Server>时,访问第二个迭代器会触发Segmentation Fault(段错误)。
程序流程:
- 实例化3个Server对象并设置端口号
- 通过TcpServer的
pushNewServer方法将对象存入私有成员std::list<Server> _servers,该方法实现:
void TcpServer::pushNewServer(const Server& server) { _servers.push_back(server); };
- 创建迭代器遍历列表至末尾时触发段错误,完整代码如下:
#include <string> #include <iostream> #include <list> # define GET 1 # define POST 2 # define DELETE 3 # define SET -1 # define CLEAR -2 # define ALL_METHODS 7 #define bitset(byte,nbit) (byte |= (1 << nbit)) #define bitclear(byte,nbit) (byte &= ~(1 << nbit)) #define bitcheck(byte,nbit) (byte & (1 << nbit)) class Server; class Location; class TcpServer { public: TcpServer(const std::string& filename){(void)filename;}; ~TcpServer(){}; /*GETTERS*/ std::list<Server> getServers(void) const {return _servers;}; /*SETTERS*/ void pushNewServer(const Server& server){_servers.push_back(server);}; private: TcpServer(const TcpServer& rhs); TcpServer& operator=(const TcpServer& rhs); TcpServer(); std::list<Server> _servers; /* data */ }; class Location { public: Location() :_location_options(0),_body_size(0),_index(""),_root_dir(""),_uri(""),_server(0){}; Location(const Location& rhs) { _location_options = rhs._location_options; _body_size = rhs._body_size; _root_dir = rhs._root_dir; _index = rhs._index; _uri = rhs._uri; _sub_locations = rhs._sub_locations; _server = rhs._server; } Location& operator=(const Location& rhs) { if (this == &rhs) return *this; _location_options = rhs._location_options; _body_size = rhs._body_size; _root_dir = rhs._root_dir; _index = rhs._index; _uri = rhs._uri; _sub_locations = rhs._sub_locations; _server = rhs._server; return *this; } ~Location(){}; /*GETTERS*/ unsigned int& getLocationsOptions(void) {return _location_options;}; const unsigned int& getBodySize(void) const {return _body_size;}; const std::string& getRootDir(void) const {return _root_dir;}; const std::string& getIndex(void) const {return _index;}; const std::string& getUri(void) const {return _uri;}; std::list<Location> getSubLocations(void) const {return _sub_locations;}; const Server* getServer(void) const {return _server; }; /*Setters*/ void setBodySize(const unsigned int& body) { _body_size = body; }; void setIndex(const std::string& index) { _index = index; }; void setRootDir(const std::string& root_dir) { _root_dir = root_dir; }; void setUri(const std::string& uri) { _uri = uri; }; void pushNewLocation(const Location& location) { _sub_locations.push_back(location); }; void setServer(Server *server) { _server = server; }; void setLocationOption(const unsigned int& nbit, char actions) { if (actions == SET) bitset(_location_options, nbit); else if (actions == CLEAR) bitclear(_location_options, nbit); }; /*MEMBER FUNCTION*/ bool checkBits(const unsigned int& nbit) const { return (bitcheck(_location_options, nbit) > 0); } private: unsigned int _location_options; unsigned int _body_size; std::string _index; std::string _root_dir; std::string _uri; std::list<Location> _sub_locations; Server *_server; }; class Server { public: Server() :_serv_options(0),_port(0),_body_size(0),_root_dir(""),_index(""){}; Server(const Server& rhs) { _serv_options = rhs._serv_options; _body_size = rhs._body_size; _port = rhs._port; _root_dir = rhs._root_dir; _index = rhs._index; _server_names = rhs._server_names; _locations = rhs._locations; } Server& operator=(const Server& rhs) { if (this == &rhs) return *this; _serv_options = rhs._serv_options; _body_size = rhs._body_size; _port = rhs._port; _root_dir = rhs._root_dir; _index = rhs._index; _server_names = rhs._server_names; _locations = rhs._locations; return *this; } ~Server(){}; /*GETTERS*/ unsigned int getServOptions(void) const {return _serv_options;}; const unsigned int& getPort(void) const {return _port;}; const unsigned int& getBodySize(void) const {return _body_size;}; const std::string& getRootDir(void) const {return _root_dir;}; const std::string& getIndex(void) const {return _index;}; std::list<Location> getLocations(void) const {return _locations;}; std::list<std::string> getServerNames(void) const {return _server_names;}; /*Setters*/ void setPort(const unsigned int& port) { _port = port; }; void setBodySize(const unsigned int& body) { _body_size = body; }; void setRootDir(const std::string& root_dir) { _root_dir = root_dir; }; void setIndex(const std::string& index) { _index = index; }; void pushNewServerName(const std::string& server_name) { _server_names.push_back(server_name); }; void pushNewLocation(const Location& location) { _locations.push_back(location); }; void setServOption(const unsigned int& nbit, char actions) { if (actions == SET) bitset(_serv_options, nbit); else if (actions == CLEAR) bitclear(_serv_options, nbit); }; /*MEMBER FUNCTION*/ bool checkBits(const unsigned int& nbit) const { return (bitcheck(_serv_options, nbit) > 0); } private: unsigned int _serv_options; unsigned int _port; unsigned int _body_size; std::string _root_dir; std::string _index; std::list<std::string> _server_names; std::list<Location> _locations; }; int main (int argc, char **argv) { try { TcpServer tcp_servers(argc > 1 ? argv[1] : ""); Server a; Server b; Server c; a.setPort(1500); b.setPort(2500); c.setPort(3500); tcp_servers.pushNewServer(a); tcp_servers.pushNewServer(b); tcp_servers.pushNewServer(c); std::list<Server>::iterator it; for (it = tcp_servers.getServers().begin(); it != tcp_servers.getServers().end() ; it++) { std::cout << &*it << std::endl; std::cout << "-----------NEXT_SERV------------- "; } } catch(const std::exception& e) { std::cerr << e.what() << std::endl; } }
问题原因
核心错误出在TcpServer::getServers()的返回值设计:
std::list<Server> getServers(void) const {return _servers;};
该方法返回的是**_servers的副本**,而非原列表的引用。在遍历循环中:
for (it = tcp_servers.getServers().begin(); it != tcp_servers.getServers().end() ; it++)
- 第一次调用
getServers()生成临时列表副本,it指向这个副本的起始位置 - 临时副本在语句结束后立即被销毁,
it变成悬空迭代器 - 后续循环中操作
it++或访问*it时,实际操作的是已释放的内存,直接触发段错误 - 同时每次调用
getServers()都会生成新副本,it != tcp_servers.getServers().end()比较的是两个不同副本的迭代器,逻辑完全错误
解决方案
修改getServers()的返回值为const引用,避免返回副本:
const std::list<Server>& getServers(void) const {return _servers;};
若需要修改列表内容,可额外提供非const版本的引用返回:
std::list<Server>& getServers(void) {return _servers;};
同时在遍历前获取一次列表引用,避免重复调用生成不必要的副本:
const std::list<Server>& servers = tcp_servers.getServers(); for (std::list<Server>::const_iterator it = servers.begin(); it != servers.end() ; ++it) { std::cout << &*it << std::endl; std::cout << "-----------NEXT_SERV-------------\n"; }
修正后的完整代码
#include <string> #include <iostream> #include <list> # define GET 1 # define POST 2 # define DELETE 3 # define SET -1 # define CLEAR -2 # define ALL_METHODS 7 #define bitset(byte,nbit) (byte |= (1 << nbit)) #define bitclear(byte,nbit) (byte &= ~(1 << nbit)) #define bitcheck(byte,nbit) (byte & (1 << nbit)) class Server; class Location; class TcpServer { public: TcpServer(const std::string& filename){(void)filename;}; ~TcpServer(){}; /*GETTERS*/ const std::list<Server>& getServers(void) const {return _servers;}; std::list<Server>& getServers(void) {return _servers;}; /*SETTERS*/ void pushNewServer(const Server& server){_servers.push_back(server);}; private: TcpServer(const TcpServer& rhs); TcpServer& operator=(const TcpServer& rhs); TcpServer(); std::list<Server> _servers; }; class Location { public: Location() :_location_options(0),_body_size(0),_index(""),_root_dir(""),_uri(""),_server(0){}; Location(const Location& rhs) { _location_options = rhs._location_options; _body_size = rhs._body_size; _root_dir = rhs._root_dir; _index = rhs._index; _uri = rhs._uri; _sub_locations = rhs._sub_locations; _server = rhs._server; } Location& operator=(const Location& rhs) { if (this == &rhs) return *this; _location_options = rhs._location_options; _body_size = rhs._body_size; _root_dir = rhs._root_dir; _index = rhs._index; _uri = rhs._uri; _sub_locations = rhs._sub_locations; _server = rhs._server; return *this; } ~Location(){}; /*GETTERS*/ unsigned int& getLocationsOptions(void) {return _location_options;}; const unsigned int& getBodySize(void) const {return _body_size;}; const std::string& getRootDir(void) const {return _root_dir;}; const std::string& getIndex(void) const {return _index;}; const std::string& getUri(void) const {return _uri;}; std::list<Location> getSubLocations(void) const {return _sub_locations;}; const Server* getServer(void) const {return _server; }; /*Setters*/ void setBodySize(const unsigned int& body) { _body_size = body; }; void setIndex(const std::string& index) { _index = index; }; void setRootDir(const std::string& root_dir) { _root_dir = root_dir; }; void setUri(const std::string& uri) { _uri = uri; }; void pushNewLocation(const Location& location) { _sub_locations.push_back(location); }; void setServer(Server *server) { _server = server; }; void setLocationOption(const unsigned int& nbit, char actions) { if (actions == SET) bitset(_location_options, nbit); else if (actions == CLEAR) bitclear(_location_options, nbit); }; /*MEMBER FUNCTION*/ bool checkBits(const unsigned int& nbit) const { return (bitcheck(_location_options, nbit) > 0); } private: unsigned int _location_options; unsigned int _body_size; std::string _index; std::string _root_dir; std::string _uri; std::list<Location> _sub_locations; Server *_server; }; class Server { public: Server() :_serv_options(0),_port(0),_body_size(0),_root_dir(""),_index(""){}; Server(const Server& rhs) { _serv_options = rhs._serv_options; _body_size = rhs._body_size; _port = rhs._port; _root_dir = rhs._root_dir; _index = rhs._index; _server_names = rhs._server_names; _locations = rhs._locations; } Server& operator=(const Server& rhs) { if (this == &rhs) return *this; _serv_options = rhs._serv_options; _body_size = rhs._body_size; _port = rhs._port; _root_dir = rhs._root_dir; _index = rhs._index; _server_names = rhs._server_names; _locations = rhs._locations; return *this; } ~Server(){}; /*GETTERS*/ unsigned int getServOptions(void) const {return _serv_options;}; const unsigned int& getPort(void) const {return _port;}; const unsigned int& getBodySize(void) const {return _body_size;}; const std::string& getRootDir(void) const {return _root_dir;}; const std::string& getIndex(void) const {return _index;}; std::list<Location> getLocations(void) const {return _locations;}; std::list<std::string> getServerNames(void) const {return _server_names;}; /*Setters*/ void setPort(const unsigned int& port) { _port = port; }; void setBodySize(const unsigned int& body) { _body_size = body; }; void setRootDir(const std::string& root_dir) { _root_dir = root_dir; }; void setIndex(const std::string& index) { _index = index; }; void pushNewServerName(const std::string& server_name) { _server_names.push_back(server_name); }; void pushNewLocation(const Location& location) { _locations.push_back(location); }; void setServ
相关产品推荐
相关产品推荐

