C ++(Windows)向量为啥会出现内存错误?
Posted
技术标签:
【中文标题】C ++(Windows)向量为啥会出现内存错误?【英文标题】:C++ (Windows) How come vectors get memory wrong?C ++(Windows)向量为什么会出现内存错误? 【发布时间】:2011-08-09 07:18:12 【问题描述】:好吧,也许我正在做一些非常愚蠢的事情,但我很生气。一整天我一直在处理向量中存储指向我自己的类的指针,但它们(大部分时间)搞砸了。有时当我遍历它们时,我最终会得到另一个向量的变量,而有时我会从记忆中得到一些完全无意义的东西。
以下是部分代码:
vector<TCPClientProtocol*> clients;
vector<TCPClientProtocol*> robots;
//this function gets names from "robots" and sends them to all the "clients"
void sendRobotListToClients()
//collect the list:
int numRobots = robots.size();
char *list = (char*)malloc(numRobots * USERNAME_SIZE);
for(int i=0; i<numRobots; i++)
int namelen = strlen(robots[i]->name);
memcpy(&list[i*USERNAME_SIZE], robots[i]->name,
namelen);
if(namelen < USERNAME_SIZE)
list[i*USERNAME_SIZE + namelen] = (char)0;
//send it to all clients:
int numClients = clients.size();
for(int i=0; i<numClients; i++)
int result = clients[i]->sendRobotList(list, numRobots);
if(result < 0)
cout<<"Failed sending refreshed list to "
<<clients[i]->name<<"."<<endl;
delete list; //forgot to add this before
//How I created vectors:
vector<TCPClientProtocol*> clients;
vector<TCPClientProtocol*> robots;
//and this is how I add to them:
robots.push_back(robot);
基本上,我没有得到我想要的内存。我正在考虑使用数组,或者制作我自己的课程,但我想要动态存储。不过,这很愚蠢……
robots.push_back(robot1);
clients.push_back(client1);
举个例子:
TCPClientProtocol *robot = new TCPClientProtocol(mySocket); //create with existing socket
robot->name = "robot1";
cout<<robot->name<<endl; //prints correctly
robots.push_back(robot);
... //do some other stuff (this IS multithreaded, mind you)
cout<<robots[0]->name<<endl; //prints something strange
TCPClientProtocols 派生自侦听服务器套接字,该套接字返回套接字并将它们放入类中。虽然指针位于向量内,但我在类中使用套接字函数,即
robot->sendData(buffer, lenght);
robot->receiveData(buffer, length);
等等。之后,我去尝试再次引用它们。我不能把所有的代码都放在这里……超过 500 行。
然后我收集机器人名称,我要么得到乱码,要么得到客户的名字。无论如何,感谢您的帮助。
编辑:我特意对其进行了测试,以确切了解它在每一步都在做什么。它打印出我想要的确切名称/字符串(机器人-> 名称)。然而,在它被推入向量后,我从向量中取出完全相同的指针,它不再指向正确的名称,而是完全给了我其他东西。这就是为什么我很困惑。当不涉及向量时,我明显糟糕的内存操作效果很好。
直接加到向量上的函数:
void addRobotToList(TCPClientProtocol *robot)
//add robot to list
robots.push_back(robot);
cout<<"Added "<<robot->name<<endl;
调用这个函数的函数(警告:长!)——是的,我的意思是把它分开,但这有点像草稿:
DWORD WINAPI AcceptThread(void* parameter)
TCPClientProtocol* cl = (TCPClientProtocol*)parameter;
TCPHeader *head = new TCPHeader;
loginInfo *logInfo = new loginInfo;
//Read header.
int result = cl->receiveHeader(head);
if(result < 0)
return -1;
//Check data. Expected: DATATYPE_CONNETION_REQUEST
// and check protocol version.
if( head->version != (char)PROTOCOL_VERSION ||
head->type != (char)DATATYPE_CONNECTION_REQUEST ||
head->size != (int)CONNECTION_REQUEST_LENGTH)
goto REJECT;
cout<<"Accepted connection."<<endl;
result = cl->requestLoginInfo();
if(result < 0)
goto CONNECTIONLOST;
//Read header.
result = cl->receiveHeader(head);
if(result < 0)
goto CONNECTIONLOST;
if(head->type != DATATYPE_LOGIN_INFO)
goto REJECT;
//read login information
result = cl->receiveLoginInfo(logInfo);
if(result < 0)
goto CONNECTIONLOST;
//check for authentication of connector. If failed, return.
if(!authenticate(logInfo))
goto REJECT;
cout<<"Authenticated."<<endl;
//add name to robot/client
cl->name = logInfo->username;
//Check for appropriate userType and add it as a variable:
switch(logInfo->userType)
case USERTYPE_ROBOT:
cl->userType = USERTYPE_ROBOT;
cl->isClient = false;
cout<<"Robot connected: "<<cl->name<<endl;
break;
case USERTYPE_CLIENT:
cl->userType = USERTYPE_CLIENT;
cl->isClient = true;
cout<<"Client connected: "<<cl->name<<endl;
break;
default:
goto REJECT;
break;
//Send a phase change to PHASE 2:
result = cl->notifyPhaseChange(2);
if(result < 0)
goto CONNECTIONLOST;
//if client, send robot availability list and listen for errors
// and disconnects while updating client with refreshed lists.
if(cl->isClient)
//add client to clients list:
clients.push_back(cl);
//send initial list:
int numRobots = robots.size();
char *list = (char*)malloc(numRobots * USERNAME_SIZE);
for(int i=0; i<numRobots; i++)
cout<<(i+1)<<" of "<<numRobots<<": "<<robots[i]->name<<endl;
int namelen = strlen(robots[i]->name);
memcpy(&list[i*USERNAME_SIZE], robots[i]->name,
namelen);
if(namelen < USERNAME_SIZE)
list[i*USERNAME_SIZE + namelen] = (char)0;
result = cl->sendRobotList(list, numRobots);
if(result < 0)
removeClientFromList(cl->name);
goto CONNECTIONLOST;
cout<<"Sent first robot list."<<endl;
//wait to receive a ROBOT_SELECTION, or error or disconnect:
result = cl->receiveHeader(head);
if(result < 0)
removeClientFromList(cl->name);
goto CONNECTIONLOST;
if(head->type != DATATYPE_ROBOT_SELECTION)
removeClientFromList(cl->name);
goto REJECT;
//receive and process robot selection
char *robotID = (char*)malloc(ROBOT_SELECTION_LENGTH+1);
result = cl->receiveRobotSelection(robotID);
robotID[USERNAME_SIZE] = (char)0;
robotID = formatUsername(robotID);
if(result < 0)
removeClientFromList(cl->name);
goto CONNECTIONLOST;
cout<<"Got a selection.."<<endl;
//get the robot and remove it from list
TCPClientProtocol *robot = removeRobotFromList(formatUsername(robotID));
cout<<"Removal win."<<endl;
//check robot status:
if(robot == NULL)
//TRY AGAIN
cout<<"Oh mai gawsh, robot is NULL!"<<endl;
getch();
else if(!robot->tcpConnected())
//TRY AGAIN
cout<<"Oh mai gawsh, robot DISCONNECTED!"<<endl;
getch();
else
cout<<"Collected chosen robot: "<<robot->name<<endl;
//request stream socket information from client
result = cl->requestStreamSocketInfo();
if(result < 0)
removeClientFromList(cl->name);
addRobotToList(robot); //re-add the robot to availability
goto CONNECTIONLOST;
result = cl->receiveHeader(head);
if(result < 0)
removeClientFromList(cl->name);
addRobotToList(robot); //re-add the robot to availability
goto CONNECTIONLOST;
//check for datatype
if(head->type != DATATYPE_STREAM_SOCKET_INFO)
removeClientFromList(cl->name);
addRobotToList(robot); //re-add the robot to availability
goto REJECT;
//receive stream socket info:
char *ip = (char*)malloc(20);
int port;
result = cl->receiveStreamSocketInfo(ip, &port);
if(result < 0)
removeClientFromList(cl->name);
addRobotToList(robot); //re-add the robot to availability
goto CONNECTIONLOST;
cout<<"Got ip: "<<ip<<" port: "<<port<<endl;
//send stream socket information to robot
result = robot->sendStreamSocketInfo(ip, port);
if(result < 0)
//RETURN CLIENT TO 'step 5'
removeClientFromList(cl->name);
delete robot;
goto CONNECTIONLOST;
//send phase changes to both, and use this thread
// to monitor signals from client to robot.
result = cl->notifyPhaseChange(3);
if(result < 0)
addRobotToList(robot); //re-add the robot to availability
removeClientFromList(cl->name);
goto CONNECTIONLOST;
result = robot->notifyPhaseChange(3);
if(result < 0)
//RETURN CLIENT TO 'step 5'
removeClientFromList(cl->name);
delete robot;
goto CONNECTIONLOST;
cout<<"PHASE 3 INITIATED"<<endl;
removeClientFromList(cl->name);
//run a thread sending connections from CLIENT to ROBOT.
while(true)
cout<<"Listening for header..."<<endl;
//read next header from client
result = cl->receiveHeader(head);
cout<<"Got something"<<endl;
if(result < 0)
cout<<"Failed read."<<endl;
delete robot;
goto CONNECTIONLOST;
if(head->type != DATATYPE_COMMAND)
cout<<"Not a command. Protocol mismatch"<<endl;
continue;
cout<<"Gots header"<<endl;
//read command
result = cl->receiveCommand();
if(result < 0)
//RESET ROBOT!
delete robot;
goto CONNECTIONLOST;
cout<<"Got data."<<endl;
result = robot->sendCommand((char)result);
if(result < 0)
//RESET CLIENT!
delete robot;
goto CONNECTIONLOST;
//spawn a thread for robot-to-client and client-to-robot comm,
// possibly just client-to-robot.
//send a phase change (to phase 3) - in thread!
//if robot, add to robot list and wait.
else
//add robot to robots list:
addRobotToList(cl);
delete head;
delete logInfo;
return 0;
//Clean up variables and send reject message
REJECT:
cout<<"Connection rejected."<<endl;
cl->sendRejection();
delete cl;
delete head;
delete logInfo;
return -1;
CONNECTIONLOST:
cout<<"Connection lost."<<endl;
delete cl;
delete head;
delete logInfo;
return -1;
【问题讨论】:
如何在向量中存储指针 - 请提供代码示例? 您能否澄清一下您在哪里弄乱了数据?是在sendRobotList
吗?
矢量行为异常的可能性极小。您更有可能误解了它们的行为方式,和/或您在代码中犯了错误。在这种情况下,错误可能在于您填充向量的方式。
我只是对它们做了一个“push_back(item)”。从文档中,我知道你应该这样做,但当然,这是我第一次使用向量,所以我不知道。
显示将指针添加到向量的完整函数。
【参考方案1】:
您的代码是 C 和 C++ 的可怕组合,当然所有错误都在 C 部分:)。所以不要责怪向量,而是看看那些可怕的低级内存操作。
在我看来
无法保证不会超出列表范围 不保证列表会以空值终止 列表内存泄漏开始使用 std::string 似乎是最好的建议。
【讨论】:
..或ostringstream
生成“列表”
字符串都是以空值结尾的。我编写了自己的代码。我使用 char* 而不是字符串的原因是因为我使用处理字节/字符的协议类通过套接字发送所有这些东西以发送所有内容。
@Richard: 只是以char
发送出去,您需要将它们存储为char
。
@Richard:然后在发送之前将其转换为字节数组。使用相同的参数,您可以使用汇编程序,因为它在编译后无论如何都会在汇编程序中结束:)
@Richard,没有理由不使用字符串。只需在您发送/接收字符串的位置转换为 char 数组(或 char 向量)。直接内存操作很难,你不是第一个出错的程序员,这就是为什么我们有向量、字符串等。【参考方案2】:
看看这里的代码需要指出的一些事情是:
您应该使用new
而不是malloc
。
您应该使用 智能指针,而不是在向量中存储原始指针。
使用iterators
迭代向量内容。
使用std::string
而不是char*
【讨论】:
【参考方案3】:已解决:错误是删除 loginInfo 结构导致擦除其中的名称对象,从而使名称变量中的指针无效。感谢所有推荐使用字符串的人,他们确实解决了问题,而且使用起来没有那么危险。
【讨论】:
以上是关于C ++(Windows)向量为啥会出现内存错误?的主要内容,如果未能解决你的问题,请参考以下文章
开机的时候总出现C:/WINDOWS/system32/pqepy.dll内存分配错误
玩C F的时候,为啥现在经常出现 out of memory ,就退了游戏,PS:我最近安装了个“火线魔盒”。