Добрый день!
Задача: создавать очень быстро std::shared_ptr для объекта небольшого класса.
Подскажите пожалуйста как правильно работать с std::shared_ptr && allocator/deallocator чтобы избежать двойного выделения памяти для самого объекта и control block.
#include <iostream>
#include <memory>
#include "memory_allocator.hpp"
class Frame
{
public:
Frame() {std::cout << __func__ << std::endl;};
~Frame() {std::cout << __func__ << std::endl;};
};
//----------------------------------------------------------------------
int main()
{
MemoryAllocator<Frame> allocator;
auto deleter = [&](Frame* frame) {
std::cout << "[deleter called] " << frame << std::endl;
allocator.deallocate(frame);
};
auto ptr = allocator.allocate();
std::shared_ptr<Frame> frame(ptr, deleter, allocator);
return 0;
}
Простой аллокатор, запиленный по примерам в интернете:
template<typename T>
class MemoryAllocator
{
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
MemoryAllocator() noexcept {std::cout << "ctor " << this << std::endl;};
MemoryAllocator(const MemoryAllocator&) noexcept {std::cout << "copy ctor " << this << std::endl;};
template<typename U>
MemoryAllocator(const MemoryAllocator<U>&) noexcept {std::cout << "template copy ctor " << this << std::endl;};
~MemoryAllocator() noexcept {std::cout << "dtor " << this << std::endl;};
pointer allocate() {
auto ptr = static_cast<pointer>(::operator new(sizeof(T)));
std::cout << this << " " <<__func__ << " " << ptr << std::endl;
return ptr;
}
//----------------------------------------------------------------------
pointer allocate(size_type n, const void* = 0) {
auto ptr = static_cast<pointer>(::operator new(n * sizeof(T)));
std::cout << this << " " << __func__ << " " << ptr << " " << n << std::endl;
return ptr;
}
//----------------------------------------------------------------------
void deallocate(pointer ptr) {
std::cout << this << " " << __func__ << " " << ptr << std::endl;
}
//----------------------------------------------------------------------
void deallocate(pointer ptr, size_type) {
std::cout << this << " " << __func__ << " " << ptr << std::endl;
}
};
Получаем такой вывод.
ctor 0x7fff54e392d8
0x7fff54e392d8 allocate 0x1074010
copy ctor 0x7fff54e39298
copy ctor 0x7fff54e39238
copy ctor 0x7fff54e391d8
template copy ctor 0x7fff54e39170
0x7fff54e39170 allocate 0x1074030 1
copy ctor 0x1074040
dtor 0x7fff54e39170
dtor 0x7fff54e391d8
dtor 0x7fff54e39238
dtor 0x7fff54e39298
[deleter called] 0x1074010
0x7fff54e392d8 deallocate 0x1074010
template copy ctor 0x7fff54e391c0
dtor 0x1074040
0x7fff54e391c0 deallocate 0x1074030
dtor 0x7fff54e391c0
dtor 0x7fff54e392d8
Как видно, вроде все хорошо, сам объект и control блок выделяются через аллокатор и удаляются так же.
Но!
Почему здесь там много всяких copy ctor ?
Как можно использовать только один аллокатор и почему он так много раз копируется ?
P.S. извините за скудные познания в memory allocation, первый раз сталкиваюсь. Спасибо!