5

std::map の問題に直面しています。理由は不明ですが、map への挿入によって「不適切な割り当て」例外が発生することがあります。

以下は、マップに挿入するために使用する関数です。

BOOL Add2WaitList(Object<LPVOID> *newObj)
{
    try
    {
        _set_se_translator( trans_func );
        m_syncWQ.Lock();
        if (m_waitingQueue.count(newObj->uid)>0)
        {
            m_syncWQ.Unlock();
            return FALSE;
        }
        m_waitingQueue[newObj->uid] = *newObj; <-- failing here
        m_syncWQ.Unlock();
        return TRUE;
    }
    catch(std::exception &ex){
        ...
    }
    catch(SE_Exception &e){
        ...
    }
    catch(...){
        ...
    }
}

誰かがこれを解決する方法を教えてもらえますか?

注: 再現する手順を特定できません。

THXお早めに!

オブジェクトとマップに関する詳細を追加:

template <typename T>
struct Object{
public:
    void Kill()
    {
        if (response!=NULL)
            delete response;
        if (object!=NULL)
            delete object;
    }

    enum objType;
    std::string uid;
    enum status;
    double p;
    enum execType;
    T object;
    LPVOID response;
};

std::map<std::string,Object<LPVOID>> m_waitingQueue;
4

4 に答える 4

2

std::map 操作が問題を引き起こすことは明らかです

m_waitingQueue[newObj->uid] = *newObj;

これは実際にはマップの挿入操作であり、バックグラウンドでメモリを割り当てる可能性があります: STL マップはどのように割り当てられますか? スタックまたはヒープ?考えられる理由の 1 つは、メモリの割り当てが不正な割り当ての例外につながることです: C++ での不正な割り当ての例外

しかし、このコード自体は、舞台裏で何が起こっているのかを説明するものではありません。変数はグローバルであり、この関数の外で何かが行われる可能性があるため、「m_waitingQueue」に関連するより多くの情報が必要だと思います。

于 2013-07-19T08:26:19.707 に答える
2

例外std::bad_allocは「operator new失敗」を意味します。そのため、 on (これについては何も知りません) またはマップの挿入演算子 (その可能性が非常に高い)operator newによって呼び出されます。operator*newObj

operator[]具体的には、いくつかのパラメーター k を使用してマップ上で呼び出す場合

k がコンテナー内のどの要素のキーとも一致しない場合、関数はそのキーを持つ新しい要素を挿入し、マップされた値への参照を返します。これにより、マップされた値が要素に割り当てられていない場合でも、コンテナーのサイズが常に 1 増加することに注意してください (要素は既定のコンストラクターを使用して構築されます)。

(ここに文書化されているように)。

Map::operator[]障害に対する強力な保証を提供します。

Strong guarantee: if an exception is thrown, there are no changes in the container.

ただし、例外がスローされないことは保証されません (つまり、スローされないという保証はありません)。

operator new例外をスローする理由は、さまざまな性質のものである可能性があります。ただし、要約すると次のようになります。

throws bad_alloc if it fails to allocate storage.

とはいえ、JamesKanze がコメントで示唆しているように:

std::bad_alloc のもう 1 つの考えられる理由は、未定義の動作です。たとえば、彼が自由空間アリーナを破壊した場合。そして現実的には、実際にメモリが不足している場合、失敗する割り当てはさまざまです。体系的にここにある場合、何よりも Object のコピー コンストラクターに問題があると思われます。

operator newプログラムの他の部分に何らかのバグがあるため、ストレージの割り当てに失敗したことを意味します。への呼び出しの直前に (非常に) 大量のデータのチャンクを割り当てることにより、(統計学者がそれを呼び出すように) 彼の null 仮定に対してデバッグできますoperator[]。ダミーの割り当てが失敗しない場合は、コピー コンストラクターにバグがあると自信を持って言えます。

于 2013-07-19T08:08:32.273 に答える
0

おそらくAdd2WaitList(Object<LPVOID>)、メモリがなくなるまで何百万回も呼び出されているだけです。

その場合、原因はコードのどこかにあります。たとえば、無限ループまたは回帰の形です。別の考えられる原因は、Object誤ってすべての が異なるになった場合uidです。これはuid、たとえば、 が初期化されていない数値から派生した場合に発生する可能性があります。

于 2013-07-19T08:59:10.680 に答える
0

operator new()関数は、要求されたメモリを見つけることができません。この関数は、new式から、または のアロケータで直接呼び出すことができますstd::map

コンテキストに関する情報は提供しません。本当の問題は、この特定の時点で常に失敗するかどうかです。本当にメモリが不足している場合 (たとえば、メモリ リークが原因で)、他の割り当てにもヒットすることが予想されます。他の可能性としては、この関数を呼び出す直前にフリー スペース アリーナを破損している、またはコピー コンストラクターに問題があり、Object<LPVOID>無制限のメモリが要求されるか、フリー スペース アリーナが破損し、次の割り当てが失敗する可能性があります。 . このオブジェクトを別の場所にコピーしますか? ポインターで渡すという事実は、おそらくそうではないことを示唆しています。その場合、これが問題が発生する場所になります。

編集:

のコードを投稿したのでObjectObject 使用する元はどこですか? また、ポインターは通常何を指し、動的に割り当てられる場合、削除はどのように管理されるのでしょうか?

Objectユーザー定義のコンストラクターがないため、ポインターにランダムなジャンクが含まれる場合があることを意味します。また、ランダム ポインタを削除することは、空き領域を破壊する非常に良い方法です。

Lock()また、同期プリミティブ (および)のように見えるものがあることに気付きましたUnlock()。他にどこで m_waitingQueue使われていますか?m_waitingQueueが別のスレッドからアクセスできる場合はm_waitingQueue、同じ同期オブジェクト ( m_syncWQ) を使用して、 へのすべてのアクセスを同期する必要があります。ここで変更しているときに別のスレッドで変更しようとするm_waitingQueueと、未定義の動作が発生する可能性があります (キュー オブジェクトが想定されていない場所に書き込みます)。

于 2013-07-19T08:23:36.543 に答える