Okay, maybe I'm doing something fatally stupid, but I'm mad. All day I've been dealing with vectors storing in them pointers to my own class, but they mess up (much of the time). Sometimes when I traverse through them, I end up getting the other vector's variable, other times I get some complete nonsense from memory.
Here's some of the code:
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);
Basically, I'm not getting the memory I want. I'm considering going to arrays, or making my own class, but I wanted dynamic storage. This is silly, though...
robots.push_back(robot1);
clients.push_back(client1);
As an example:
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
The TCPClientProtocols are derived from a listening server socket that returns sockets and puts them into the class. While the pointers sit inside the vectors, I use socket functions in the class, i.e
robot->sendData(buffer, lenght);
robot->receiveData(buffer, length);
etc. Afterwards, I go try to reference them again. I can't put all the code here... it's over 500 lines long.
Then I collect the robot names, and I either get gibbrish, or the client's name. Anyway, thanks for your help.
EDIT: I deliberately tested it to see exactly what it was doing at every step. It printed out the exact name/string (robot->name) that I wanted. After it was pushed into the vector, however, I took tha开发者_JAVA百科t exact same pointer from within the vector, it no longer pointed to the right name, instead gave me something else entirely. That's why I'm confused. My apparently bad memory manipulation works well enough when vectors aren't involved.
The function that adds directly to the vector:
void addRobotToList(TCPClientProtocol *robot){
//add robot to list
robots.push_back(robot);
cout<<"Added "<<robot->name<<endl;
}
The function that calls this function (warning: long!) - and yes, I mean to divide it up but this is sort of a draft:
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;
}
You code is a horrible mix of C and C++ and of course all the errors are in the C parts :). So don't blame vectors but instead look at all that horrible low level memory manipulation.
Looks to me that
- There's no guarantee that you won't overflow the bounds of list
- There's no guarantee that list will be null terminated
- The list memory leaks
Start using std::string would seem to be the best advice.
Some of the things to point out with one look at the code here will be:
- You should be using
new
instead ofmalloc
. - You should be using smart pointers not storing raw pointers in your vector.
- Use
iterators
for iterating over the vector contents. - Use
std::string
and notchar*
SOLVED: The error was deleting the loginInfo struct lead to erasing the name object inside of it, thus invalidating the pointers in the name variable. Thanks to all who recommended using strings, they definitely solved the problem and they're not as risky to use.
精彩评论