Изучаю умные указатели и абстрактные базовые классы.
Есть следующий интерфейс:
#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).
Не могу понять в чем проблема.
Что происходит в строке 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 для умных указателей, как и для любых классов, вообще очень плохая практика. Не делайте так.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
всем неравнодушным! Заранее благодарю за помощь или желание помочьЕсть сайт: https://lucklife-business
у меня есть макет (Фото предоставляю ниже), шапку сверстал самостоятельно, осталось сделать вторую часть макета (главную часть), подскажите...