C ++ (Windows) Hvordan kommer vektorer at få hukommelse forkert?

Indlæg af Hanne Mølgaard Plasc

Problem



Okay, måske gør jeg noget dårligt dumt, men jeg er sur. Hele dagen har jeg arbejdet med vektorer, der lagrer i deres pointer til min egen klasse, men de ødelægger (meget af tiden). Nogle gange når jeg krydser gennem dem, ender jeg med at få den anden vektor 's variable, andre gange jeg få nogle komplette nonsens fra hukommelsen.


Her er nogle af koden:


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);


Dybest set får jeg ikke den hukommelse, jeg ønsker. Jeg overvejer at gå til arrayer eller lave min egen klasse, men jeg ønskede dynamisk opbevaring. Dette er dumt, selvom ...


robots.push\_back(robot1);
clients.push\_back(client1);


Som et eksempel:


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 er afledt af en lytte-serverstik, der returnerer stikkontakter og sætter dem i klassen. Mens pointerne sidder inde i vektorerne, bruger jeg fatningsfunktioner i klassen, dvs.


robot->sendData(buffer, lenght);
robot->receiveData(buffer, length);


mv. Efterfølgende vil jeg forsøge at henvise dem igen. Jeg kan ikke sætte alle koden her ... den er over 500 linjer lang.


Så samler jeg robotnavnet, og jeg får enten gibbrish eller kundens navn. Anyway, tak for din hjælp.


EDIT: Jeg har bevidst testet det for at se præcis, hvad det gjorde ved hvert trin. Det udskrev det nøjagtige navn/streng (robot-> navn), som jeg ønskede. Efter at den blev skubbet ind i vektoren tog jeg den samme nøjagtige samme peger inde fra vektoren, det pegede ikke længere på det rigtige navn, men gav mig i stedet helt andet. Det er derfor jeg er forvirret. Min tilsyneladende dårlige hukommelsesmanipulation virker godt nok, når vektorer ikke er involveret.


Funktionen, der tilføjer direkte til vektoren:


void addRobotToList(TCPClientProtocol *robot){
    //add robot to list
    robots.push\_back(robot);
    cout<<"Added "<<robot->name<<endl;
}


Funktionen, der kalder denne funktion (advarsel: lang!) - og ja, jeg mener at dele det op, men det er sådan et udkast:


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;
}

Bedste reference


Du kode er en forfærdelig blanding af C og C ++ og selvfølgelig er alle fejlene i C-delene :). Så skyll ikke vektorer, men i stedet se på alt det forfærdelige lavt niveau hukommelsesmanipulation.


Ser mig det



  • Der er ingen garanti for at du vandt 'oversvider grænsen for listen

  • Der er ingen garanti for, at listen vil blive afbrudt

  • Listenhukommelsen lækker



Begynd at bruge std :: streng synes at være det bedste råd.

Andre referencer 1


Nogle af de ting at påpege med et kig på koden her vil være:



  • Du skal bruge new i stedet for malloc.

  • Du skal bruge smarte pegere ikke gemme råpegepinde i din vektor.

  • Brug iterators til iterering over vektorindholdet.

  • Brug std::string og ikke char*


Andre referencer 2


LØSET: Fejlen var at slette loginInfo struct-ledningen for at slette navneobjektet inde i den og dermed ugyldiggøre pointerne i navnevariablen. Takket være alle, der anbefalede at bruge strenge, løste de helt klart problemet, og de 'er ikke så risikable at bruge.