11

プロジェクトでメモリ管理を行いたい。オペレーターのグローバルな新規/削除は必要ないので、単純なメモリー割り当てを実装します。これは私のコードです:

class IAllocator
{
public:
    void* Alloc( unsigned int size )
    {
        1. alloc memory.
        2. trace alloc.
    }
    void Dealloc( void* ptr )
    {
        1. free memory.
        2. erase trace info.
    }
    template< typename T >
    void Destructor( T* ptr )
    {
        if ( ptr )
            ptr->~T();
    }
};
// macro for use easy.
# define MYNEW( T ) new ( g_Allocator->Alloc( sizeof( T ) ) ) T
# define MYDEL( ptr ) if (ptr) { g_Allocator->Destructor(ptr); g_Allocator->Dealloc(ptr); }

次に、MYNEWを使用してオブジェクトを構築し(メモリリークをチェックするために割り当て情報をトレースします)、MYDELを使用してオブジェクトを破棄します(トレース情報を消去します)。

すべてが正常に見えます...しかし、このメソッドを多重継承クラスに使用しようとすると、非常に深刻な問題が見つかりました。以下の私のテストコードを見てください:

class A { ... };
class B { ... };
class C : public A, public B { ... };

C* pkC = MYNEW( C );
B* pkB = (B*)pkA;
MYDEL( pkB );

pkBとpkAのアドレスが等しくありません。そのため、メモリは正しく解放されず、allocトレース情報もcoorectを消去しません...ああ...

この問題を解決する方法はありますか?</ p>

4

2 に答える 2

7

ptrポリモーフィック クラスのインスタンスを指している場合、がdynamic_cast<void*>(ptr)指す最も派生したオブジェクトへのポインタになりますptr。つまり、この動的キャストは、割り当てられたアドレスへのポインターを生成します。

ただし、使用g_Allocator->Dealloc(dynamic_cast<void*>(ptr))は実行可能なソリューションではありません。問題は、非クラス オブジェクト (たとえば、プリミティブ) または非ポリモーフィック クラスのインスタンスを指しているdynamic_cast<void*>(ptr)場合は違法です。ptr

できることは、SFINAE を使用して、この動的キャストをポリモーフィック クラスへのポインターに使用するが、非クラス オブジェクトおよび非ポリモーフィック クラスのインスタンスへのポインターには静的キャストを使用する関数を作成することです。Boost (および現在は C++11) は、この点で役立つ型特性を提供is_class<T>します。is_polymorphic<T>

例:

template <typename T, bool is_poly>
struct GetAllocatedPointerHelper {
   static void* cast (T* ptr) { return ptr; }
};

template <typename T>
struct GetAllocatedPointerHelper<T, true> {
   static void* cast (T* ptr) { return dynamic_cast<void*>(ptr); }
};

template<typename T>
inline void*
get_allocated_pointer (T* ptr)
{
   const bool is_poly = Boost::is_polymorphic<T>::value;
   return GetAllocatedPointerHelper<T, is_poly>::cast(ptr);
}
于 2012-12-04T15:13:27.597 に答える
4

基本クラスの new および delete 演算子をオーバーライドして、そのクラスからカスタム アロケータが必要なすべてのクラスを派生させることができます。簡単なサンプルに従う:

#include <cstdio>
#include <cstdlib>

class Base
{
    public:
        virtual ~Base(){};

        void* operator new(size_t size){return malloc(size);}
        void operator delete(void* pointer){printf("\n%x\n", pointer); free(pointer);}
};

class A : public virtual Base
{
    public:
        ~A(){printf("~A");};
};

class B : public virtual Base
{
    public:
        ~B(){printf("~B");};
};

class C : public A, public B
{
    public:
        ~C(){printf("~C");};
};

int main()
{
    C* c = new C();
    printf("%x\n", c);

    B* b = dynamic_cast<B*>(c);
    printf("%x\n", b);

    delete b;

    return 0;
}

考えられる出力の 1 つは次のとおりです。

5831d0 5831d4 ~C~B~A 5831d0

この場合、オペレーターは受信した正しいアドレスを削除します。

于 2012-12-04T15:07:21.547 に答える