Семантика перемещения, любопытно повторяющийся шаблон шаблона и утечка памяти

Я реализовал вариант любопытно повторяющегося шаблона шаблона:

#include "stdafx.h"

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <stdlib.h>

template<typename T>
struct Indexed
    {
private:
    static int s_maxIndex;
    static std::map<int, T> s_map;

    int m_index;
    void SetNewIndex () { m_index = ++s_maxIndex; }

protected:
    Indexed (T&& t)
        {
        SetNewIndex ();
        s_map.insert (std::pair<int, T> (m_index, std::move (t)));
        }

    T&                                      GetMappedRef () { return s_map[m_index]; }
    static T&                               GetMappedRef (int index) { return s_map[index]; }

public:
    int                                     GetIndex () const { return m_index; }
    static std::map<int, Indexed> const&    GetAll () { return s_map; }
    static void                             Clear () { s_map.clear (); }
    };

template<typename T>
int Indexed<T>::s_maxIndex = 0;

template<typename T>
std::map<int, T> Indexed<T>::s_map;

struct MyObj
    {
    int m_myData;
    MyObj () = default;
    MyObj (int data)
        :m_myData (data)
        {
        }
    };

struct MyObjHandler : public Indexed<MyObj>
    {
    MyObjHandler (int value)
    :Indexed (MyObj (value))
        {
        }

    MyObj& GetObjRef ()
        {
        return GetMappedRef ();
        }

    static MyObj& GetObjRef (int index)
        {
        return GetMappedRef (index);
        }
    };

void test ()
    {
    MyObjHandler objH1 (4), objH2 (5);
    std::cout << objH1.GetIndex () << ", " << objH2.GetIndex () << std::endl;
    std::cout << objH1.GetObjRef().m_myData << ", " << objH2.GetObjRef().m_myData << std::endl;
    }

int _tmain (int argc, _TCHAR* argv[])
    {
    test ();

    _CrtDumpMemoryLeaks ();

    system ("pause");
    return 0;
    }

Вот два примера, когда использование «MyObjHandler» вместо «MyObj» имеет смысл:

  1. Для представления графа, в котором каждый узел связан с экземпляром «MyObj». Мы сохраняем в каждом узле графа индекс и используем глобальное сопоставление для получения соответствующего экземпляра «MyObj».
  2. Создание экземпляра «MyObj» в области делает этот экземпляр выпадающим из области действия в конце области:

    недействительным CreateObj () {

    объект MyObj;

    //операции над объектом;

    } //объект выходит за рамки

Но я хочу сохранить этот экземпляр для дальнейшего использования. Поэтому мне нужно использовать силу семантики перемещения.

Вроде работает, но дает утечки памяти:

Обнаружены утечки памяти!

Сброс объектов ->

{216} обычный блок по адресу 0x0063D1A0, длина 24 байта. Данные: ‹ c H c c

A8 D0 63 00 48 D1 63 00 A8 D0 63 00 00 00 CD CD

{215} обычный блок по адресу 0x0063D148, длина 24 байта. Данные: ‹ c c c

A8 D0 63 00 A8 D0 63 00 A0 D1 63 00 01 00 CD CD

{214} нормальный блок по адресу 0x0063D100, длина 8 байт. Данные: ‹@ > 40 A3 14 01 00 00 00 00

{213} normal block at 0x0063D0A8, 24 bytes long. Data:

48 D1 63 00 48 D1 63 00 A0 D1 63 00 01 01 CD CD

Дамп объекта завершен.

Почему?


person Brainless    schedule 01.04.2016    source источник


Ответы (1)


думаю нормально. Вы можете попробовать закомментировать вызов функции test, утечка памяти все равно есть (меньше, но все же есть).

На мой взгляд, _CrtDumpMemoryLeaks некорректно идентифицирует статическую карту как утечку памяти — она была выделена в начале программы и используется до сих пор. Это поведение соответствует указанному здесь:

Когда встречается неосвобожденный блок, _CrtDumpMemoryLeaks вызывает _CrtMemDumpAllObjectsSince для вывода информации обо всех объектах, выделенных в куче с начала выполнения программы.

Если вы закомментируете статическую карту, утечка памяти исчезнет.

person Ionel POP    schedule 01.04.2016