lundi 4 novembre 2019

std::unique_ptr is NOT zero cost

I have setup, similar to this:

There is class similar to vector (it is implemented using std::vector).

It contains pointers to int's.

I am using my own custom allocator.

The vector does not create elements, but it can destroy elements.

In order to destroy it needs to call non static method Allocator::deallocate(int *p).

If I do it with manual livetime management, I can call Allocator::deallocate(int *p) manually. This works, but is not RAII.

Alternatively, I can use std::unique_ptr with custom deleter. However if I do so, the size of array became double, because each std::unique_ptr must contain pointer to the allocator.

Is there any way I can do it without doubling the size of the vector?

Note i do not want to templatize the class.

Here is best RAII code I come up.

#include <functional>
#include <cstdlib>
#include <memory>



struct MallocAllocator{
    template<class T>
    static T *allocate(size_t size = sizeof(T) ) noexcept{
        return reinterpret_cast<T *>( malloc(size) );
    }

    // this is deliberately not static method
    void deallocate(void *p) noexcept{
        return ::free(p);
    }

    // this is deliberately not static method
    auto getDeallocate() noexcept{
        return [this](void *p){
            deallocate(p);
        };
    }
};



struct S{
    std::function<void(void *)> fn;

    S(std::function<void(void *)> fn) : fn(fn){}

    auto operator()() const{
        auto f = [this](void *p){
            fn(p);
        };

        return std::unique_ptr<int, decltype(f)>{ (int *) malloc(sizeof(int)), f };
    }
};



int main(){
    MallocAllocator m;

    S s{ m.getDeallocate() };

    auto x = s();

    printf("%zu\n", sizeof(x));
}

Aucun commentaire:

Enregistrer un commentaire