C++ マップのクリア メモリ リークの問題

マップ値にはポインタが格納されます

マップに付属するclear()関数は、マップに格納されている内容をすべてクリアしますが、マップの値にポインタが格納されている場合、内部の値はクリアされず、メモリリークが発生します。ポインタはイテレータを使用する必要があります。空です。

値がポインタであるマップを削除するには、消去反復削除を使用します
。反復子を正しく使用するようにしてください。反復子が失敗すると、プログラムがクラッシュします。

std::map<int, HHH*> test_map;
HHH* h1 = new HHH;
HHH* h2 = new HHH;
test_map[0] = h1;
test_map[1] = h2;


// 删除
std::map<int, HHH*>::iterator iter;
for (iter = test_map.begin(); iter != test_map.end();)
{
    
    
    delete iter->second;
    iter->second = nullptr;
    // 删除迭代器元素先加加再删,否则迭代器失效程序崩溃!!!(必须iter++不可以++iter)
    test_map.erase(iter++);
}

マップ値はポインターではなく格納されます

std::map<int,int> test_map;
test_map[0] = 0;
test_map[1] = 0;

// 删除
test_map.clear(); //值为指针不要这样删除

clear() 関数を呼び出す前に、イテレータを通じて値内のポインタの値を削除します。

	std::map<int, HHH*> test_map;
    HHH* h1 = new HHH;
    HHH* h2 = new HHH;
    test_map[0] = h1;
    test_map[1] = h2;

    // 删除
    std::map<int, HHH*>::iterator iter;
    for (iter = test_map.begin(); iter != test_map.end();)
    {
    
    
        delete iter->second;
        iter->second = nullptr;
        // 删除迭代器元素先加加再删,否则迭代器失效程序崩溃!!!(必须iter++不可以++iter)
        iter++;
    }
    test_map.clear();

マップに保存されるのはスマート ポインターです

スマートポインタを使用している場合は、別途削除する必要はなく、スマートポインタが自動的にメモリを解放します。

std::map<int, std::shared_ptr<int>> m_map;
m_map[0] = std::make_shared<int>();
delete m_map[0]; //错误

マップをクリアしてメモリを解放します

同じマップを複数回使用する必要がある場合は、使用するたびにクリアしてください。複数回使用すると、マップ領域が解放されないためにメモリ リークが発生する可能性があるため、スワップを使用してクリアする必要があります。

メモリ エラーにより次のようなメッセージが表示される場合:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()
(gdb) bt
#0  0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()
#1  0x00000000010ca2b8 in tcmalloc::SLL_TryPop(void**, void**) ()
#2  0x00000000010ca715 in tcmalloc::ThreadCache::FreeList::TryPop(void**) ()
#3  0x00000000011ebe6c in tc_newarray ()

STL コンテナが clear() メソッドを呼び出すと、通常はコンテナ内のすべてのオブジェクトが破棄されるだけで、コンテナ自体のメモリは解放されません。つまり、カゴの中の商品を取り除いても、カゴのスペースはそのまま残り、次回新たに物を収納する際に再度スペースを申請する必要がなくなります。つまり、clear() の後、コンテナのサイズは 0 になりますが、容量は変わりません。空のコンテナを swap() することで、コンテナが占有している容量を完全に解放します。

#include<map>
#include<vector>
#include<string>
#include <iostream>
#include <time.h>
using namespace std;
 
class useTest
{
    
    
public:
    useTest() {
    
    };
    map<string,string> testMap;
    vector<string> testVertor;
    string id;
};
 
void clearData(map<int, useTest>& needClearMap)
{
    
    
    clock_t  startt = clock();
 
    //分别通过去注释测试下面四种情况
 
    //使用clear
    //needClearMap.clear();
 
    //使用swap
    map<int, useTest> uu;
    needClearMap.swap(uu);
 
    //使用erase
    //needClearMap.erase(needClearMap.begin(), needClearMap.end());
 
    //使用for erase
    //for (auto iter = needClearMap.begin(); iter != needClearMap.end(); iter = needClearMap.erase(iter)) {}
    double sec = double(clock() - startt) / CLOCKS_PER_SEC;
    std::cout << "In Clear Cost Time:" << sec << endl;
}
 
void test()
{
    
    
    map<int, useTest> needClearMap;
    for (size_t i = 0; i <= 10000; ++i)
    {
    
    
        useTest uT;
        for (size_t ii = 0; ii <= 1000; ++ii)
        {
    
    
            uT.testMap[to_string(ii)] = "我是测试,我是测试,我就是测试string";
            uT.testVertor.push_back("我也是测试,我也是测试,我就是测试string");
        }
        uT.id = to_string(i);
        //cout << i << endl;
        needClearMap[i] = uT;
    }
    clock_t  startt = clock();
    clearData(needClearMap);
    double sec = double(clock() - startt) / CLOCKS_PER_SEC;
    std::cout << "clearData Cost Time:" << sec << endl;
}
 
int main()
{
    
    
    for (size_t i = 0; i < 10; ++i)
    {
    
    
        test();
    }
    getchar();
}

特定のマップをクリアする場合は、スワップが最も効率的で、時間もほとんどかかりません。ただし、関数全体を終了する場合、スワップで転送された一時オブジェクトを解放するのにある程度の時間がかかります。消去効率はクリアよりわずかに高くなります。for ループを介して消去する方が効率的のようです。

map、set、unowned_map などのコンテナーの場合、clear() または swap() を呼び出しても実際にはメモリを解放できません。多くの場所で言及されていますが、この現象 (メモリが保持される) は正常であり、心配する必要はありません。ただし、さまざまなデータ構造を保存するために大量のヒープ メモリが使用されると、深刻なメモリの断片化が発生し、メモリ リークが発生します。

#include <iostream>
#include <map>
#include <malloc.h>
using namespace std;
void func()
{
    
    
        map<int,string> mp;
        int i = 5000000;
        while(i--)
            mp.insert(make_pair(i,string("hell000o")));
        map<int,string>().swap(mp); //swap
}
int main()
{
    
    
        func();
        cout <<"done."<<endl;
        malloc_trim(0);
        while(1);
}
 

malloc_trim(0);他のプロセスで使用できるように、空きヒープ メモリをオペレーティング システムに返す行を追加するだけです。

おすすめ

転載: blog.csdn.net/qq_36314864/article/details/132716800