Vote count: 0
I'm wondering what is the best way to work around a pointer offset issues when using a custom allocator for C++. Let's consider an example:
struct A { int i; virtual ~A() = default; };
struct B { int j; virtual ~B() = default; };
struct C : A, B { int k; virtual ~C() = default; };
auto p1 = std::make_unique<C>();
std::unique_ptr<B> p2 = std::move(p1);
In this case p2.get() is different from p1.get(), due to the multiple inheritance offset applied. If both unique_ptrs use a custom deleter, which forwards the contained pointer to some custom allocator, the pointer to deallocate will be different than the pointer returned form the allocation, which is problematic.
To combat this, I've made a workaround deleter which basically calls a lambda which does the right cast:
template<class T>
class MemoryManagerDeleter
{
public:
MemoryManagerDeleter(MemoryManagerPtr manager) noexcept
: mMemoryManager{std::move(manager)}
, mDeleteFunc{[=](auto pointer) {
pointer->~T();
mMemoryManager->deallocate(pointer);
}}
{
assert(mMemoryManager);
}
template<class U>
MemoryManagerDeleter(const MemoryManagerDeleter<U> &other) noexcept
: mMemoryManager{other.mMemoryManager}
, mDeleteFunc{[=](auto pointer) {
const auto cast = static_cast<U *>(pointer);
cast->~U();
mMemoryManager->deallocate(cast);
}}
{
assert(mMemoryManager);
}
MemoryManagerDeleter(const MemoryManagerDeleter &) = default;
inline void operator()(T *pointer) const noexcept
{
if (pointer != nullptr)
mDeleteFunc(pointer);
}
MemoryManagerDeleter &operator =(const MemoryManagerDeleter &) = default;
private:
MemoryManagerPtr mMemoryManager;
std::function<void (T *)> mDeleteFunc;
template<class> friend class MemoryManagerDeleter;
};
There must be a better way to do this. It feels like an awful hack.
asked 29 secs ago
Custom allocator pointer offset from multiple inheritance
Aucun commentaire:
Enregistrer un commentaire