我想要做的内存管理在我的项目。 我不希望运营商全球新/删除,所以我实现一个简单的内存alloctor。 这是我的代码:
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的地址不等于。 所以内存不会释放正确的,页头跟踪信息将不会清除coorect太...哦...
有没有什么办法可以解决这个问题呢?
如果ptr
指向一个多态类,的一个实例dynamic_cast<void*>(ptr)
将导致一个指向最派生对象通过指向ptr
。 换句话说,这个动态铸造产生的指针作为分配地址。
然而,使用g_Allocator->Dealloc(dynamic_cast<void*>(ptr))
不是一个可行的解决方案。 的问题是, dynamic_cast<void*>(ptr)
是非法的,如果ptr
点到非类对象(例如,图元)或一个非多态性类的一个实例。
你可以做的是使用SFINAE创建使用为指针多态类这种动态转换,但使用的指针非类对象和非多态类的实例静态浇铸的功能。 升压(现在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);
}
你可以尝试覆盖运营商新的和删除一个基类并从中获得你想要从你的类自定义分配器所有类。 下面一个简单的示例:
#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;
}
一个可能的输出是:
5831d0 5831d4〜C〜乙〜甲5831d0
在这种情况下,运营商删除收到正确的地址。