多くのカスタム ヒープ アロケータがある環境では、通常、元のアドレスをvoid*
カスタム スマート ポインター内にキャッシュする必要がありますか?
後でAllo
特定のメモリ ブロックのアロケータ ( )を識別するにはcontent
:-
ブロックが割り当てられたら、その近くにハック情報 (meta-data
およびAllo*
)を格納する必要があると思います。
割り当てを解除したいときはvoid*
、void*
ポインタを差し引いて、Allo*
たとえば
template<class T>class StrongPointer{
public: void* content;
public: ~StrongPointer(){
Allo* allo=static_cast<Allo*>((void*)(static_cast<char*>(content)-4));
//^ 32-bit system
allo->deallocate(content);
}
public: void get(){ return static_cast<T*>(content); }
}
動作するはずです。
ただし、これはキャストをサポートしたいときに壊れますStrongPointer<Derived>
-> StrongPointer<Base2>
。
( MI(多重継承)のC++仮想テーブルレイアウトによる)
class Base1{/*some fields */};
class Base2{/*some fields */};
class Derived : public Base1,public Base2{};
たとえば、willをキャストStrongPointer<Derived>
した結果は、もはやの場所のすぐ隣にはありません。StrongPointer<Base2>
StrongPointer<Base2>::content
Allo*
template<class T1,class T2> StrongPointer<T2> cast(StrongPointer<T1>&& t1){
StrongPointer<T2> r;
r.content=static_cast<T2*>(t1.get());
//^ location change, so "content-(4 bytes)" doesn't point to Allo* anymore
return r;
}
私の意見では、いくつかの回避策があります。
Allo*
すべての強力なポインター内に格納します。またはAllo* + 1
割り当てられたコンテンツの実際のアドレスを反映するストアそれはすべて次のように要約されます。-
本当に別の変数を内部に保存する必要がありStrong_Pointer<T>
ますか
これは、邪魔にならず、次のようなファット ポインターを使用せずにこれを整理する方法shared_ptr
です (ファット ポインターが問題ない場合はshared_ptr
、 を使用するだけですが、それらを避けたいと思います)。この例では、カスタム スマート ポインターを使用していません。どんな種類のポインターでも使用できます。カスタム アロケータを使用する場合は、常に「make」関数を使用することだけを覚えておく必要があります。
#include <cstdlib>
#include <cstddef>
#include <iostream>
#include <memory>
#include <cstring>
struct Alloc;
struct UnalignedControlBlock
{
int magic1;
Alloc* allocator;
std::size_t size;
char magic2[19];
};
union ControlBlock
{
UnalignedControlBlock ucb;
std::max_align_t aligner;
};
struct Alloc
{
static Alloc global_allocator;
static void* allocate(std::size_t size)
{
void* p = ::operator new (size + sizeof(ControlBlock));
ControlBlock* cb = static_cast<ControlBlock*>(p);
cb->ucb.allocator = &global_allocator;
cb->ucb.magic1 = 42;
cb->ucb.size = size;
std::strcpy(cb->ucb.magic2, "Hey there!");
std::cout << "Allocate: block: " << cb << " size: " << size << " magic1: " << cb->ucb.magic1 << " magic2: " << cb->ucb.magic2 << " allocator: " << cb->ucb.alloca
return cb+1;
}
static void deallocate (void* p)
{
ControlBlock* cb = static_cast<ControlBlock*>(p);
cb--;
std::cout << "Deallocate: block: " << cb << " size: " << cb->ucb.size << " magic1: " << cb->ucb.magic1 << " magic2: " << cb->ucb.magic2 << " allocator: " << cb->u
::operator delete (cb);
}
};
template <class T>
struct Allocated : T
{
template <class ... Arg>
Allocated(Arg ... arg) : T(arg ...) {}
void* operator new (size_t size) { return Alloc::allocate(size); }
void operator delete (void* p) { return Alloc :: deallocate(p); }
};
template <class T, class ... Args>
std::unique_ptr<T> make_smart (Args ... args)
{
return std::unique_ptr<T>(new Allocated<T>(args...));
};
// 試乗
struct Test1
{
const int filler = 42;
virtual ~Test1() {
std::cout << "Test1::~Test1 " << this << " " << filler << std::endl;
}
};
struct Test2 : virtual Test1
{
const int filler = 43;
virtual ~Test2() {
std::cout << "Test2::~Test2 " << this << " " << filler << std::endl;
}
};
struct Test3 : virtual Test1
{
const int filler = 44;
virtual ~Test3() {
std::cout << "Test3::~Test3 " << this << " " << filler << std::endl;
}
};
struct Test4 : Test2, Test3
{
const int filler = 45;
virtual ~Test4() {
std::cout << "Test4::~Test4 " << this << " " << filler << std::endl;
}
};
Alloc Alloc::global_allocator;
int main ()
{
std::unique_ptr<Test1> p1 = make_smart<Test1>();
std::unique_ptr<Test1> p2 = make_smart<Test2>();
std::unique_ptr<Test1> p3 = make_smart<Test3>();
std::unique_ptr<Test1> p4 = make_smart<Test4>();
}
テスト出力
Allocate: block: 0x1817c20 size: 16 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Allocate: block: 0x1818080 size: 32 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Allocate: block: 0x18180e0 size: 32 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Allocate: block: 0x1818140 size: 48 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Test4::~Test4 0x1818170 45 Test3::~Test3 0x1818180 44 Test2::~Test2 0x1818170 43 Test1::~Test1 0x1818190 42 Deallocate: block: 0x1818140 size: 48 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Test3::~Test3 0x1818110 44 Test1::~Test1 0x1818120 42 Deallocate: block: 0x18180e0 size: 32 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Test2::~Test2 0x18180b0 43 Test1::~Test1 0x18180c0 42 Deallocate: block: 0x1818080 size: 32 magic1: 42 magic2: Hey there! allocator: 0x6052e9 Test1::~Test1 0x1817c50 42 Deallocate: block: 0x1817c20 size: 16 magic1: 42 magic2: Hey there! allocator: 0x6052e9
これは、継承用に調整されたポインターからの正しいメタデータの回復を示しています。デストラクタが仮想の場合、カスタムのデリータは必要ありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加