这些有什么区别?(涉及IT技术)

3
有人可以解释一下下面使用的方法在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个回答

4
在第一种情况下,pUser 是在堆栈上创建的,并且在其名称超出作用域时(即在下一个闭合花括号处)将自动删除。通常来说,将指向堆栈对象的指针插入容器是不明智的,因为对象将在容器仍然具有指向它的值时停止存在。这可能会导致崩溃,在最好的情况下。在最坏的情况下,它可能会导致代码中遥远部分的错误和难以定位的错误。

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

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

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

如果必须使用指针而不是实际对象本身,请使用第一种方法。当您使用new时,内存将持续存在,直到您删除它(或让另一个对象来处理它,例如共享指针)。堆栈对象在超出作用域时立即被销毁。


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(指针!!)不可用(已删除),但内存仍被占用,因此mUserMap中的指针仍然有效!


哇,太感谢大家了!我不知道竟然有这么多人愿意提供帮助!我会继续发布我的问题,期待成为像你们一样的专家。再次感谢! - Vinicius Horta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接