2012-06-12 201 views
3

任何人都可以请解释一下在地图容器中插入一个新对象的下面使用的方法的区别吗?我已经知道指针和这样的,我真的不深入到虚拟内存中,只有基础知识(地址等)这些有什么区别?

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

回答

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:除非您明确要求不会发出异常,否则会引发异常。

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(对象)不可用(删除),指针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(指针!!)不可用(删除),内存仍然声称这样指针mUserMapis有效!

+0

哇,谢谢你!我不知道有这么多人愿意帮忙!我会继续发布我期待成为专家的问题。再次感谢! –

4

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

1

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

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

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