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:我最近安装了个“火线魔盒”。

为啥这个代码在 w.show() 调用中会出现段错误?

为啥在 C 中使用错误的格式说明符会使我的程序在 Windows 7 上崩溃?

运行X-scan为啥会提示缺少NPPTools.dll

php使用redis为啥总是会出现错误?