std::shared_ptr и memory allocator
От: lnkuser  
Дата: 25.03.16 16:28
Оценка:
Добрый день!


Задача: создавать очень быстро 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, первый раз сталкиваюсь. Спасибо!
Re: std::shared_ptr и memory allocator
От: watchmaker  
Дата: 25.03.16 17:17
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Подскажите пожалуйста как правильно работать с std::shared_ptr && allocator/deallocator чтобы избежать двойного выделения памяти для самого объекта и control block.


std::allocate_shared
Re[2]: std::shared_ptr и memory allocator
От: lnkuser  
Дата: 25.03.16 17:27
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, lnkuser, Вы писали:


L>>Подскажите пожалуйста как правильно работать с std::shared_ptr && allocator/deallocator чтобы избежать двойного выделения памяти для самого объекта и control block.


W>
W>std::allocate_shared
W>


при std::allocate_shared не получится указать deleter и вывод примерно такой же, тоже много ctor && dtor...
Отредактировано 25.03.2016 17:29 lnkuser . Предыдущая версия .
Re[3]: std::shared_ptr и memory allocator
От: watchmaker  
Дата: 25.03.16 18:05
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Здравствуйте, watchmaker, Вы писали:


W>>Здравствуйте, lnkuser, Вы писали:


L>>>Подскажите пожалуйста как правильно работать с std::shared_ptr && allocator/deallocator чтобы избежать двойного выделения памяти для самого объекта и control block.


W>>
W>>std::allocate_shared
W>>


L>при std::allocate_shared не получится указать deleter


Конечно не получится! В этом весь смысл. Хоть какая-то защита от выстрела в ногу. Или как по-твоему deleter может ужиться с вышепроцитированным условием про shared_ptr и аллокацию/деаллокацию памяти одновременно под объект и под control block? Это же взаимоисключающие стратегии поведения.

Или нужно не выделения памяти под объект и control block единым участком своим аллокатором? А вопрос в чём-то другом?

L> и вывод примерно такой же, тоже много ctor && dtor...


Ну и что? Аллокаторы должны копироваться ­— они и копируются. Как они иначе должны своё состояние сохранять?
А если состояния у аллокатора нет — так вообще проблема отсутствует: никого не волнует, например, миллиарды копирований std::allocator, если каждое из них стоит ровно 0 времени и 0 памяти.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.