这些有什么区别?

时间:2012-06-12 19:01:13

标签: c++ pointers map

有人可以解释一下下面使用的方法在地图容器中插入新对象的区别吗?我已经知道了指针等等,我不是真的深入虚拟内存,只有基础知识(地址等)。

#include "StdAfx.h"
#include <windows.h>
#include <cstdlib>
#include <iostream>
#include <map>

using namespace std;

class CUser
{
public:
    CUser() { Init(); };
    ~CUser() {};
public:
        BOOL m_bActive;
        BOOL m_bLoggedIn;
        SYSTEMTIME m_sysTime;

        void Init();
};


void CUser::Init()
{
    (*this).m_bActive = FALSE;
    m_bLoggedIn = FALSE;
    GetSystemTime( &m_sysTime );
}

int main(int argc, char *argv[])
{

    map<DWORD, CUser*>mUserMap;


    //what is the difference between this
    {   
        CUser pUser;
        pUser.m_bActive = FALSE;
        pUser.m_bLoggedIn = FALSE;
        GetSystemTime( &pUser.m_sysTime );
        mUserMap.insert( make_pair( 351, &pUser ) );
    }
    //and this?
    {
        CUser *pUser = new CUser;
        if( pUser )
        {
            pUser->m_bActive = TRUE;
            pUser->m_bLoggedIn = TRUE;
            GetSystemTime( &pUser->m_sysTime );
            mUserMap.insert( make_pair( 351, pUser ) );
        }
    }

/*  map<DWORD, CUser*>::iterator it = mUserMap.find( 351 );
    if( it == mUserMap.end() )
        std::cout << "Not found" << std::endl;
    else
    {
        CUser *pUser = it->second;
        if( pUser )
            std::cout << pUser->m_sysTime.wHour << std::endl;
    } */


    return 0;
}

4 个答案:

答案 0 :(得分:4)

在第一种情况下,在堆栈上创建pUser,当其名称超出范围时(即在下一个结束的大括号中)将自动删除。一般来说,将指向堆栈对象的指针插入容器是不明智的,因为当容器仍然有一个指向它的值时,该对象将不复存在。这可能会导致最佳情况下的崩溃。在最坏的情况下,它可能导致不稳定并且很难在代码的远端部分找到错误。

答案 1 :(得分:3)

//what is the difference between this
{   
    CUser pUser;
    pUser.m_bActive = FALSE;
    pUser.m_bLoggedIn = FALSE;
    GetSystemTime( &pUser.m_sysTime );
    mUserMap.insert( make_pair( 351, &pUser ) );
}

这将创建一个本地对象:您的pUser变量仅存在 此块的范围内,并且在到达最后}时不再存在。这意味着它的析构函数被调用,它所居住的内存被回收并可以被重用。

现在,当您在地图中存储指向此短期对象的指针时,您将存储问题。如果在此块的结束}之后的任何时间取消引用该指针,则表示您正在调用未定义的行为。它可能会奏效。它有时可能会起作用,然后开始失败。基本上,这是一个逻辑错误和不可预测的错误的良好来源。

//and this?
{
    CUser *pUser = new CUser;
    if( pUser )
    {
        pUser->m_bActive = TRUE;
        pUser->m_bLoggedIn = TRUE;
        GetSystemTime( &pUser->m_sysTime );
        mUserMap.insert( make_pair( 351, pUser ) );
    }
}

这里你明确地创建了一个比封闭范围更长的实例,一切都很好。您不需要检查new是否返回NULL:它会抛出异常,除非您明确要求不这样做。

答案 2 :(得分:1)

{   
    CUser pUser;
    pUser.m_bActive = FALSE;
    pUser.m_bLoggedIn = FALSE;
    GetSystemTime( &pUser.m_sysTime );
    mUserMap.insert( make_pair( 351, &pUser ) );
}
//pUser is not available here

pUser(Object)不可用(已删除),mUserMap中的指针无效!

{
    CUser *pUser = new CUser;
    if( pUser )
    {
        pUser->m_bActive = TRUE;
        pUser->m_bLoggedIn = TRUE;
        GetSystemTime( &pUser->m_sysTime );
        mUserMap.insert( make_pair( 351, pUser ) );
    }
}
//pUser is not available here

pUser(Pointer !!)不可用(已删除),内存仍然声明,因此mUserMap中的指针有效!

答案 3 :(得分:1)

这里的区别在于,对new的调用创建的对象是在堆而不是堆栈上创建的。这意味着一旦指针超出范围,分配的内存仍然存在于堆上,您可以通过存储在地图中的指针安全地引用它。

在第一种情况下,您在堆栈上创建一个对象并将其地址添加到地图中。这意味着当您本地创建的变量超出范围时,它将被销毁,并且地图中的指针现在指向不再存在的变量。这无疑会导致代码出现问题。

如果必须使用指针而不是实际对象本身,请使用第一种方法。 使用new时,内存将一直存在,直到您将其删除(或者让另一个对象像共享指针一样处理它)。堆栈对象一旦超出范围就会被销毁。