0

私は C++ アプリケーションを開発しており、std::set の内容を std::deque にコピーする必要があります。私のアプリケーションで行っていることに似たものは次のとおりです。(これは簡易版です)

class A
{
public:
    A(){};
    ~A() {};

    void UpdateDataSet(std::set<C>& _setData);

private:
    std::deque<C>   deque_Data;//contains ohlc data for the symbol   
};

void A::UpdateDataSet(std::set<C>& _setData)
{
    std::set<C>::iterator itrSet =  _setData.begin();
    std::set<C>::iterator itrSetEnd =  _setData.end();

    while(itrSet != itrSetEnd)
    {
        deque_Data.push_back(*itrSet);
        ++itrSet;
    }
}


int main()
{
    A* pA = new A();

    std::set<C> setData;
    C mC1(5,10);
    C mC2(10,20);
    C mC2(30,40);

    C.insert(mC1);
    C.insert(mC2);
    C.insert(mC3);

    pA->UpdateDataSet(setData);


    return 0;
}

ここで C は、2 つの整数を含むクラスです。上記のコードは、期待どおりに正常に動作します。しかし、問題は、valgrind memcheck を使用してコードのプロファイリングを行うと、コード ブロックの近くで失われた可能性のあるデータが指摘されることです。

deque_Data.push_back(*itrSet); 

valgrind の出力は次のとおりです。

==3469== 1,032,640 bytes in 180 blocks are possibly lost in loss record 1,337 of 1,346
==3469==    at 0x4006355: operator new(unsigned int) (vg_replace_malloc.c:214)
==3469==    by 0x46B92AF: __gnu_cxx::new_allocator<C*>::allocate(unsigned int, void const*) (new_allocator.h:88)
==3469==    by 0x46B92E7: std::_Deque_base<C, std::allocator<C> >::_M_allocate_map(unsigned int) (stl_deque.h:424)
==3469==    by 0x46B94F9: std::deque<C, std::allocator<C> >::_M_reallocate_map(unsigned int, bool) (deque.tcc:750)
==3469==    by 0x46B960B: std::deque<C, std::allocator<C> >::_M_reserve_map_at_back(unsigned int) (stl_deque.h:1444)
==3469==    by 0x46B96C5: std::deque<C, std::allocator<C> >::_M_push_back_aux(C const&) (deque.tcc:348)
==3469==    by 0x46B9822: std::deque<C, std::allocator<C> >::push_back(C const&) (stl_deque.h:1045)
==3469==    by 0x46B6B09: A::UpdateDataSet(std::set<C, std::less<C>, std::allocator<C> >&)

誰かがここでメモリの問題を見つけるのを手伝ってくれませんか. この valgrind の出力は本当にメモリ リークを意味していますか?

4

3 に答える 3

2

メインの最後に「delete pA」をしていませんでした...

于 2012-11-29T09:42:28.900 に答える
1

標準ライブラリが正しく実装されていると仮定すると、dequeによって割り当てられたメモリが割り当て解除されない理由は2つ考えられます。

  1. dequeの内部に激しくアクセスします。memset /memcpyまたはreinterpet_cast/Cスタイルのキャストを使用すると、dequeがプライベートメンバーを格納するメモリ位置(割り当てられたメモリへのポインタなど)にアクセスできる場合があります。これらのプライベートメンバーをなんらかの方法でいじると、dequeは動的に割り当てられたメモリの割り当てを解除できず、memleaksが発生する可能性があります。通常、このような攻撃的な行為は多くの種類のアクセス違反につながるため、単なるmemleaksではなくクラッシュを観察することになります。
  2. dequeデストラクタ呼び出しがありません。何らかの理由でdequeのデストラクタが呼び出されない場合、「クリーンアップ」する機会はありません。つまり、所有している動的メモリの割り当てを解除して、前述のmemleaksにつながります。あなたの場合、dequeデストラクタは、Aのデストラクタによって自動的に呼び出されます。ただし、aがあり、deque自体が無料のストア/ヒープに割り当てられている場合を除きますdeque*(以下を参照)。Aのデストラクタの呼び出しが欠落している理由は、次の1つ以上である可能性があります。
    • 欠落しているdelete:deleteはオブジェクトのデストラクタを呼び出し、オブジェクトがあった場所のメモリを解放します。その場合、オブジェクトが割り当てられて作成された場所を指す別のメモリリークが表示されます(サンプルコードではnew A()
    • deleteの代わりに呼び出すfree():freeはメモリを解放するだけで、デストラクタを呼び出しません。newとfreeを一致させないでください。非常に注意深く、何をするかを理解していない限り、C++オブジェクトでmalloc/ freeを使用しないようにしてください(新しい配置...)
    • コードからの「ジャンプ」。どういうわけかスコープから「ジャンプ」すると、コンパイラはスコープブロックの最後で自動デストラクタ呼び出しを実行できない可能性があります。コンパイラは何をすべきか、どのようにクリーンアップするかを知っているので、これは例外には適用されません。gotoでオブジェクトの有効期間の境界に違反すると、ほとんどのコンパイラがエラーを発行するため、これは'sには適用されませんgotoそれでも、使用gotoできる機能は他にもあるため、C++では使用しないようにしてください。ここで想像できる唯一の「ジャンプ」はですlongjmp。これは、スコープの境界を尊重しないC機能であるため、特にデストラクタ呼び出しの必要性を無視します。C++コードでは使用しないでください。longjmp

誰かがメモリリーク、デストラクタコールの欠落などの理由をもっと考えられる場合は、ヒントを教えてください。この回答を編集します:-)

PS:「以下を参照」の部分を見逃したのを見たばかりです。deque*では、Aの代わりにAを使用している場合はどうなりますdequeか?その場合、Aはdequeを正しく構築および破棄する責任があります。つまり、キューを作成する必要があるときはいつでもnewを呼び出します。少なくともデストラクタでdeleteを呼び出します。特に、コピー/ムーブ代入とコピー/ムーブ構築を正しく処理します。deque*ポインタ処理を台無しにして、別のmemleakが表示され、実行する呼び出しのいずれかを指しているnew dequeはずです。

于 2012-11-29T11:07:31.803 に答える
1

あなたの例には何かが欠けています.メモリリークはありません。

このコードに準拠して実行しました

 #include <set>
 #include <deque>

 class C
 {
 public:
     C (int a, int b)
         :   m_a (a)
         ,   m_b (b)
     {
     }

     bool operator <(const C& c) const
     {
         return m_a < c.m_a || (m_a == c.m_a && m_b < c.m_b);
     }

 private:
     int m_a;
     int m_b;
 };
 class A
 {
     public:
         A(){};
         ~A() {};

         void UpdateDataSet(std::set<C>& _setData);

     private:
         std::deque<C>   deque_Data;//contains ohlc data for the symbol
 };

 void A::UpdateDataSet(std::set<C>& _setData)
 {
     std::set<C>::iterator itrSet =  _setData.begin();
     std::set<C>::iterator itrSetEnd =  _setData.end();

     while(itrSet != itrSetEnd)
     {
         deque_Data.push_back(*itrSet);
         ++itrSet;
     }
 }


 int main()
 {
     A* pA = new A();

     std::set<C> setData;
     C mC1(5,10);
     C mC2(10,20);
     C mC3(30,40);

     setData.insert(mC1);
     setData.insert(mC2);
     setData.insert(mC3);

     pA->UpdateDataSet(setData);
     delete pA;


     return 0;
 }

予想どおり、valgrind は疑わしいものを報告しません

于 2012-11-29T11:19:29.923 に答える