Умные указатели и утечка памяти

110
03 декабря 2020, 21:30

Изучаю умные указатели и абстрактные базовые классы.

Есть следующий интерфейс:

#pragma once
#include <vector>
#include <initializer_list>
#include <memory>
#define PURE_VIRTUAL =0
namespace linalg {
    class _btensor;
    class vector;
    using _btensor_uptr = std::unique_ptr<_btensor>;
    class _btensor 
    {
    public:
        virtual _btensor_uptr identity_(double(*custom_norm)(const _btensor&) = nullptr) const PURE_VIRTUAL;
    };
    using dyn_array = std::vector<double>;
    using init_list = std::initializer_list<double>;
    class vector : public _btensor
    {
    public:
        dyn_array data_;
    public:
        explicit vector(const dyn_array&);
        vector(const init_list&);
        _btensor_uptr identity_(double(*custom_norm)(const _btensor&) = nullptr) const override;
    };
}

И реализация:

#include "linalg.hpp"
using namespace linalg;
vector::vector(const dyn_array& data)
    : data_(data)
{
}
vector::vector(const init_list& il)
    : data_(il)
{
}
_btensor_uptr vector::identity_(double(*custom_norm)(const _btensor &)) const
{
    using std::make_unique;
    double norm_val = (custom_norm == nullptr ? norm() : custom_norm(*this));
    dyn_array new_data(data_.size());
    for (dyn_array::size_type i = 0; i < data_.size(); ++i) new_data[i] = data_[i] / norm_val;
    return static_cast<_btensor_uptr>(make_unique<vector>(new_data));
}

Вызываю так:

#include <vld.h>
#include "linalg.hpp"
int main()
{
    using linalg::vector;
    vector v = { 1.11, 2.12, 3.99 };
    v.identity_();
    return 0;
}

Программа отрабатывает корректно, но кроме всего прочего, в отладке использую Visual Leak Detector 2.5.1, который говорит, что при вызове v.identity_() возникает утечка памяти:

WARNING: Visual Leak Detector detected memory leaks!
---------- Block 6 at 0x0000000000384F80: 16 bytes ----------
  Leak Hash: 0x9A3E07BD, Count: 1, Total 16 bytes
  Call Stack (TID 7804):
    ucrtbased.dll!malloc()
    linalg.exe!0x000000013F3C9833()
    ...
    linalg.exe!0x000000013F3CA369()
    kernel32.dll!BaseThreadInitThunk() + 0xD bytes
    ntdll.dll!RtlUserThreadStart() + 0x1D bytes
  Data:
    E8 7A 39 00    00 00 00 00    00 00 00 00    00 00 00 00     .z9..... ........
---------- Block 7 at 0x000000000038A430: 24 bytes ----------
  Leak Hash: 0xEB8C4A1B, Count: 1, Total 24 bytes
  Call Stack (TID 7804):
    ucrtbased.dll!malloc()
    linalg.exe!0x000000013F3C9833()
    ...
    linalg.exe!0x000000013F3CA369()
    kernel32.dll!BaseThreadInitThunk() + 0xD bytes
    ntdll.dll!RtlUserThreadStart() + 0x1D bytes
  Data:
    F9 12 AE E6    AE 89 CE 3F    DB 44 6A 0A    89 29 DD 3F     .......? .Dj..).?
    36 83 15 B7    59 71 EB 3F                                   6...Yq.? ........

Visual Leak Detector detected 2 memory leaks (144 bytes).

Не могу понять в чем проблема.

Answer 1

Что происходит в строке static_cast<_btensor_uptr>(make_unique<vector>(new_data)); при преобразовании unique_ptr<vector> в unique_ptr<_btensor_uptr>?
Право владения передается от указателя одного типа к указателю другого типа. Хотя физически он указывает на тот же самый адрес в памяти, информация о типе по этому адресу данных - теряется. unique_ptr в своем деструкторе, вызвал бы деструктор для vector, а новый умный указатель вызовет деструктор только для _btensor . Поскольку деструктор _btensor невиртуальный, то будут вызваны деструкторы только для членов данны btensor (их нет). Т.е. data (из vector) останется неочищенным.

Решений два: либо добавить виртуальный деструктор в _btensor , либо перейти к использованию shared_ptr вместо unique_ptr (они, при касте указателей, сохраняют функцию-делетор см. https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast ).

Прямой вызов static_cast для умных указателей, как и для любых классов, вообще очень плохая практика. Не делайте так.

READ ALSO
Не работает часть стилей

Не работает часть стилей

всем неравнодушным! Заранее благодарю за помощь или желание помочьЕсть сайт: https://lucklife-business

111
Как расположить блоки с помощью flexbox?

Как расположить блоки с помощью flexbox?

у меня есть макет (Фото предоставляю ниже), шапку сверстал самостоятельно, осталось сделать вторую часть макета (главную часть), подскажите...

99
Перенос структуры таблицы

Перенос структуры таблицы

Есть 2 таблицы, у первой такая структура:

103