繁体   English   中英

这些有什么区别?

[英]What is the difference between these?

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

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

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

//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 :除非您明确要求不这样做,否则它将抛出异常。

{   
    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中的指针有效!

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM