中止(核心转储)从 C++ 中的向量中删除元素
Aborted (core dumped) removing element from vector in c++
我正在尝试使用“MUD 游戏编程”学习 C++,并且正在研究这些示例,但是当我尝试从向量中删除连接时,出现错误:“已中止(核心已转储)”。这通常发生在从向量中删除最后一个时。我尝试过一些解决方案,例如在删除之前检查迭代器 != connlist.end() 是否存在,如果列表中只剩下一个元素,则尝试使用 connlist.clear() ,但这些不会似乎没有帮助。
我正在使用 g++ 编译并在 Cygwin 上工作。
错误发生在 connlist.erase() 处,您可以看到当用户键入“退出”时会调用它。
void NMudServer::StartListening() {
fd_set read_set;
std::vector<SocketLib::Connection>::iterator itr;
std::vector<SocketLib::Connection>::iterator itr2;
TIMEVAL zerotime;
zerotime.tv_usec = 0;
zerotime.tv_sec = 0;
char buffer[buf_len];
int err;
lsock.Listen( default_port );
if( lsock.IsListening() ) {
std::cout << "Telnet listening on port " << default_port << "." << std::endl;
} else {
std::cout << "Could not start Telnet listening socket! - Last error code: " << WSAGetLastError() << std::endl;
return;
}
while( lsock.IsListening() ) {
FD_ZERO( &read_set );
FD_SET( lsock.GetSock(), &read_set );
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
FD_SET( itr->GetSock(), &read_set );
}
int sel = select( 0x7FFFFFFF, &read_set, NULL, NULL, &zerotime );
if( sel > 0 ) {
if( FD_ISSET( lsock.GetSock(), &read_set ) ) {
SocketLib::DataSocket dsock = lsock.Accept();
SocketLib::Connection conn( dsock, buf_len );
connlist.push_back( conn );
conn.Send( "Hello!\r\n", 8 );
}
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
if( FD_ISSET( itr->GetSock(), &read_set ) ) {
err = itr->Receive();
if( err == -1 ) {
std::cout << "Socket receiving error!" << std::endl;
std::cout << "Error code: " << WSAGetLastError() << std::endl;
std::cout << "Exiting due to error." << std::endl;
CloseAllConnections(); // This is when the connection is closed. Need to only close the one connection.
break;
} else if( err == 0 ) {
itr->Close();
connlist.erase( itr );
--itr;
} else if( itr->IsReady() ) {
int size;
size = itr->GetData( buffer );
if( strcmp( buffer, "servquit\r\n" ) == 0 ) {
CloseAllConnections();
} else if( strcmp( buffer, "quit\r\n" ) == 0 ) {
itr->Close();
connlist.erase( itr ); // When you go to erase the last element, it errors
--itr;
} else {
// Echo back the data to all connections
for( itr2 = connlist.begin(); itr2 != connlist.end(); ++itr2 ) {
if( itr2->GetSock() != itr->GetSock() ) {
int err2;
itr2->Send( buffer, size );
if( err2 == -1 ) {
std::cout << "Socket sending error: " << WSAGetLastError() << std::endl;
}
} else {
itr2->Send( "\r\n", 2 );
}
} // end for
}// end if-else
itr->Reset();
} // end if-else-else
} // end if
} // end for
} // end if sel
} // end while
}
void NMudServer::CloseAllConnections() {
lsock.Close();
std::vector<SocketLib::Connection>::iterator itr;
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
itr->Close();
}
WSACleanup();
}
供参考,这本书是:
彭顿,罗恩。 MUD 游戏编程。 美国马萨诸塞州波士顿:课程技术/Cengage 学习,2003。
您正在迭代一个向量并在循环内从中擦除元素。这绝不是一个好主意。 vector::erase
使您随后用于进一步迭代的迭代器无效。
参见:https://en.cppreference.com/w/cpp/container/vector/erase
原因是向量可能 重新分配 and/or 在您擦除元素时移动元素。
可能的解决方案:
只需关闭该循环内的那些连接,然后执行 erase-remove:
connlist.erase(std::remove_if(connlist.begin(), connlist.end(), is_closed), connlist.end());
与 is_closed
类似:
is_closed = [](const SocketLib::Connection& c) {return !c.open();};
PS:我不知道 SocketLib
所以你可以稍微改变一下 is_closed
PPS: 使用 range-based 循环如 for(auto& connection : connlist) {...}
编辑:
如评论中所述,在这种情况下vector不会重新分配,其他点仍然有效。
我正在尝试使用“MUD 游戏编程”学习 C++,并且正在研究这些示例,但是当我尝试从向量中删除连接时,出现错误:“已中止(核心已转储)”。这通常发生在从向量中删除最后一个时。我尝试过一些解决方案,例如在删除之前检查迭代器 != connlist.end() 是否存在,如果列表中只剩下一个元素,则尝试使用 connlist.clear() ,但这些不会似乎没有帮助。
我正在使用 g++ 编译并在 Cygwin 上工作。
错误发生在 connlist.erase() 处,您可以看到当用户键入“退出”时会调用它。
void NMudServer::StartListening() {
fd_set read_set;
std::vector<SocketLib::Connection>::iterator itr;
std::vector<SocketLib::Connection>::iterator itr2;
TIMEVAL zerotime;
zerotime.tv_usec = 0;
zerotime.tv_sec = 0;
char buffer[buf_len];
int err;
lsock.Listen( default_port );
if( lsock.IsListening() ) {
std::cout << "Telnet listening on port " << default_port << "." << std::endl;
} else {
std::cout << "Could not start Telnet listening socket! - Last error code: " << WSAGetLastError() << std::endl;
return;
}
while( lsock.IsListening() ) {
FD_ZERO( &read_set );
FD_SET( lsock.GetSock(), &read_set );
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
FD_SET( itr->GetSock(), &read_set );
}
int sel = select( 0x7FFFFFFF, &read_set, NULL, NULL, &zerotime );
if( sel > 0 ) {
if( FD_ISSET( lsock.GetSock(), &read_set ) ) {
SocketLib::DataSocket dsock = lsock.Accept();
SocketLib::Connection conn( dsock, buf_len );
connlist.push_back( conn );
conn.Send( "Hello!\r\n", 8 );
}
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
if( FD_ISSET( itr->GetSock(), &read_set ) ) {
err = itr->Receive();
if( err == -1 ) {
std::cout << "Socket receiving error!" << std::endl;
std::cout << "Error code: " << WSAGetLastError() << std::endl;
std::cout << "Exiting due to error." << std::endl;
CloseAllConnections(); // This is when the connection is closed. Need to only close the one connection.
break;
} else if( err == 0 ) {
itr->Close();
connlist.erase( itr );
--itr;
} else if( itr->IsReady() ) {
int size;
size = itr->GetData( buffer );
if( strcmp( buffer, "servquit\r\n" ) == 0 ) {
CloseAllConnections();
} else if( strcmp( buffer, "quit\r\n" ) == 0 ) {
itr->Close();
connlist.erase( itr ); // When you go to erase the last element, it errors
--itr;
} else {
// Echo back the data to all connections
for( itr2 = connlist.begin(); itr2 != connlist.end(); ++itr2 ) {
if( itr2->GetSock() != itr->GetSock() ) {
int err2;
itr2->Send( buffer, size );
if( err2 == -1 ) {
std::cout << "Socket sending error: " << WSAGetLastError() << std::endl;
}
} else {
itr2->Send( "\r\n", 2 );
}
} // end for
}// end if-else
itr->Reset();
} // end if-else-else
} // end if
} // end for
} // end if sel
} // end while
}
void NMudServer::CloseAllConnections() {
lsock.Close();
std::vector<SocketLib::Connection>::iterator itr;
for( itr = connlist.begin(); itr != connlist.end(); ++itr ) {
itr->Close();
}
WSACleanup();
}
供参考,这本书是: 彭顿,罗恩。 MUD 游戏编程。 美国马萨诸塞州波士顿:课程技术/Cengage 学习,2003。
您正在迭代一个向量并在循环内从中擦除元素。这绝不是一个好主意。 vector::erase
使您随后用于进一步迭代的迭代器无效。
参见:https://en.cppreference.com/w/cpp/container/vector/erase
原因是向量可能 重新分配 and/or 在您擦除元素时移动元素。
可能的解决方案:
只需关闭该循环内的那些连接,然后执行 erase-remove:
connlist.erase(std::remove_if(connlist.begin(), connlist.end(), is_closed), connlist.end());
与 is_closed
类似:
is_closed = [](const SocketLib::Connection& c) {return !c.open();};
PS:我不知道 SocketLib
所以你可以稍微改变一下 is_closed
PPS: 使用 range-based 循环如 for(auto& connection : connlist) {...}
编辑:
如评论中所述,在这种情况下vector不会重新分配,其他点仍然有效。