좋아, 내가 어쩌면 멍청한 짓을하고 있을지 모르지만, 나는 화가났다. 하루 종일 나는 내 자신의 클래스에 포인터를 저장하는 벡터를 다루었지만, 많은 시간을 낭비했다. 때로는 그들을 통과 할 때, 나는 다른 벡터의 변수를 얻게되고, 다른 때는 메모리에서 완전한 말도 안되는 것을 얻습니다.C++ (Windows) 벡터가 어떻게 메모리를 잘못 처리합니까?
여기에 코드의 일부입니다 : 기본적으로
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 라인이 넘습니다.
그런 다음 로봇 이름을 수집하고 나는 gibbrish 또는 고객의 이름을 얻습니다. 어쨌든, 도와 줘서 고마워.
편집 : 모든 단계에서 정확히 무엇을하고 있었는지 확인하기 위해 의도적으로 테스트했습니다. 그것은 내가 원하는 정확한 이름/문자열 (robot-> name)을 출력했다. 그러나 벡터에 푸시 된 후 벡터 내에서 정확히 동일한 포인터를 가져 왔고 더 이상 올바른 이름을 가리 키지 않고 대신 완전히 다른 것을 제공했습니다. 그래서 혼란 스럽네. 내 명백하게 나쁜 메모리 조작은 벡터가 관련되지 않을 때 충분히 잘 작동합니다.
벡터에 직접 추가 기능 :
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;
}
포인터를 벡터에 저장하는 방법 - 코드 호소 샘플? – matekm
데이터를 엉망으로 만들 수있는 곳을 명확히 할 수 있습니까? 'sendRobotList'에 있나요? – sergio
벡터가 잘못 작동하는 것은 거의 없습니다. 그들이 어떻게 행동해야하는지, 그리고/또는 코드에서 실수를 저질렀다는 것을 오해 할 가능성이 더 큽니다. 이 경우, 실수는 벡터를 채우는 방법에 있습니다. –