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

4 に答える 4

4

最初のケースでpUserは、はスタック上に作成され、その名前がスコープ外になると(つまり、次の閉じ中括弧で)自動的に削除されます。一般的に言って、オブジェクトをスタックするためのポインタをコンテナに挿入することは賢明ではありません。コンテナがそれを指す値を持っている間、オブジェクトは存在しなくなるからです。これにより、最良の場合にクラッシュが発生する可能性があります。最悪の場合、コードの離れた部分でバグを見つけるのが不安定で困難になる可能性があります。

于 2012-06-12T19:06:34.023 に答える
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。明示的に要求しない限り、例外がスローされます。

于 2012-06-12T19:14:01.650 に答える
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(Pointer !!)は使用できません(削除されました)、メモリはまだ要求されているので、mUserMapのポインタは有効です!

于 2012-06-12T19:04:20.467 に答える
1

違いは、toの呼び出しによって作成されたオブジェクトがnew、スタックではなくヒープ上に作成されることです。これは、ポインタがスコープ外になっても、割り当てられたメモリはヒープ上にまだ存在しており、マップに格納されているポインタを介して安全に参照できることを意味します。

最初のケースでは、スタック上にオブジェクトを作成し、そのアドレスをマップに追加します。これは、ローカルで作成された変数がスコープ外になると破棄され、マップ内のポインターが、存在しなくなった変数を指すようになることを意味します。これは間違いなくコードの問題につながります。

実際のオブジェクト自体ではなくポインタを使用する必要がある場合は、最初のアプローチを使用してください。使用する場合new、メモリは削除するまで(または、共有ポインタのように別のオブジェクトに処理させるまで)存続します。スタックオブジェクトは、スコープから外れるとすぐに破棄されます。

于 2012-06-12T19:12:31.327 に答える