Собсна, сабж. Дан некий условный класс буфера(UniformBuffer), он реализует(по-крайней мере должен где-то там в задумках) SoA путь хранения данных. Внутри буфера std::tuple, который есть кортеж AlignedBuffer<какой-нибудь-тип>(раньше Uniform & Aligned были одним классом, но столкнувшись с нижеописанной проблемой я попробовал его разделить на два, не взлетело). Инициализируется кортеж в конструкторе как-то так
UniformBuffer(int64_t length)
: data(impl::AlignedBuffer<DataTypes>(length)...)
{}
и вроде даже собирается, память внутри AlignedBuffer выделяется, только вот не освобождется в конце. В этом проблема. Если собрать тестовое приложение(код ниже), то вывод в консоль будет примерно таким
allocated block(i) 93824992337520
allocated block(f) 93824992341824
allocated block(f) 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
free invoked(f) for 93824992342016
... и так до бесконечности, пока сегфолт не выскочит.
То есть метод освобождения памяти вызывается дохреналион раз, и всё на одном блоке. Вопрос, что я делаю не так? gcc (Debian 7.3.0-27) 7.3.0
+ весь код
− Скрыть
#pragma once
#if defined(__linux__)
#include <stdlib.h>
#elif defined(_WIN32)
#include <malloc.h>
#endif
#include <cstdint>
#include <memory>
#include <tuple>
#include <algorithm>
#include <iostream>
namespace tmp
{
namespace impl
{
template<typename DataType>
class AlignedBuffer
{
public:
typedef DataType data_t;
AlignedBuffer()
: length(0)
{}
AlignedBuffer(int64_t length)
: ptr(AlignedBuffer::alloc(length), AlignedBuffer::free), length(length)
{}
static DataType *alloc(int64_t count)
{
DataType *mblock = nullptr;
#if defined(__linux__)
mblock = reinterpret_cast<DataType *>(aligned_alloc(DEFAULT_ALIGNMENT, sizeof(DataType) * count));
#elif defined(_WIN32)
mblock = reinterpret_cast<DataType *>(_aligned_malloc(sizeof(DataType) * count, DEFAULT_ALIGNMENT));
#endif
if (mblock == nullptr)
throw std::bad_alloc();
std::cout << "allocated block(" << typeid(DataType).name() << ") "
<< reinterpret_cast<uintptr_t>(mblock) << std::endl;
return mblock;
}
static void free(DataType *mblock)
{
std::cout << "free invoked(" << typeid(DataType).name() << ") for "
<< reinterpret_cast<uintptr_t>(mblock) << std::endl;
#if defined(__linux__)
free(mblock);
#elif defined(_WIN32)
_aligned_free(mblock);
#endif
}
inline DataType *getPtr()
{ return this->ptr.get(); }
inline const DataType *getPtr() const
{ return this->ptr.get(); }
inline int64_t getLength() const
{ return this->length; }
private:
static const size_t DEFAULT_ALIGNMENT = 16;
std::shared_ptr<
DataType> ptr;
int64_t length;
};
}
template<typename ...DataTypes>
class UniformBuffer
{
public:
typedef std::tuple<impl::AlignedBuffer<DataTypes>...> DataTuple;
UniformBuffer()
: length(0) {}
UniformBuffer(int64_t length)
: data(impl::AlignedBuffer<DataTypes>(length)...)
{}
template<size_t index>
inline typename std::tuple_element<index, DataTuple>::type::data_t *getBlock()
{ return std::get<index>(this->data).getPtr(); }
template<size_t index>
inline const typename std::tuple_element<index, DataTuple>::type::data_t *getBlock() const
{ return std::get<index>(this->data).getPtr(); }
inline int64_t getLength() const
{ return this->length; }
private:
DataTuple data;
int64_t length;
};
}
Delfigamer
> Угадай с одного раза, какой из free вызовется на этой строке.
Чьорт, слона то я и не приметил ^_^ спасибо.