现在我的班级有一个构造函数,复制构造函数和复制赋值运算符,其中首先执行相同的操作< / strong>(分配内存)。析构函数正在释放内存。
class Register
{
public:
Register()
{
_trampoline_address = reinterpret_cast<BYTE*>(VirtualAlloc(nullptr, _trampoline_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
if (_trampoline_address == nullptr)
{
throw my_exception("Could not allocate memory for trampoline function.");
}
//....
}
~Register()
{
if (_trampoline_address != nullptr)
{
debug(VirtualFree(_trampoline_address, 0, MEM_RELEASE));
}
}
Register(const Register& other)
{
_trampoline_address = reinterpret_cast<BYTE*>(VirtualAlloc(nullptr, _trampoline_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
if (_trampoline_address == nullptr)
{
throw my_exception("Could not allocate memory for trampoline function.");
}
//...
}
Register& operator= (const Register& other)
{
_trampoline_address = reinterpret_cast<BYTE*>(VirtualAlloc(nullptr, _trampoline_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
if (_trampoline_address == nullptr)
{
throw my_exception("Could not allocate memory for trampoline function.");
}
//....
}
private:
BYTE* _trampoline_address;
static const int _trampoline_size = 20;
};
我考虑过将分配算法外包,因为我使用了3次,但我不希望相同类类型的其他实例可以访问该功能。
那么在RAII类的3个函数中分配内存的正确解决方案是什么?
答案 0 :(得分:2)
您可以创建一个private static
函数来帮助分配内存:
static BYTE* allocate()
{
BTYE* ptr = reinterpret_cast<BYTE*>(VirtualAlloc(nullptr, _trampoline_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
if (ptr == nullptr)
{
throw my_exception("Could not allocate memory for trampoline function.");
}
return ptr;
}
然后,构造函数可以简化为:
Register() : _trampoline_address(allocate()) { }
Register(const Register& other) : _trampoline_address(allocate()) { }
但是,复制赋值运算符需要更多的工作。首先,从您发布的代码中不清楚,赋值运算符的语义是什么。您是否应该将数据从RHS复制到LHS?如果没有,RHS在分配操作中扮演什么角色?您应该如何处理LHS拥有的内存?
Register& operator= (const Register& other)
{
// Prevent messing with memory when dealing with self-assignment.
if ( this != &other )
{
// Deal with the semantics of the operation.
}
return *this;
}
答案 1 :(得分:0)
你可以做以下两件事之一:
dependencies {
compile project(':Lib-AndroidLibrary')
}
函数,然后在每个构造函数中调用它。这仍然允许类的其他成员函数在构造之后调用函数,但这应该没问题(只是不要调用它!)。 子类无法调用类的私有成员,因此您应该没问题。答案 2 :(得分:0)
struct Register {
Register():
_trampoline_address(allocate())
{}
Register(Register const& o):
Register() // forward to default ctor
{
copy_data_from(o);
}
~Register() {
if (_trampoline_address)
debug(VirtualFree(_trampoline_address, 0, MEM_RELEASE));
}
Register& operator= (const Register& o) {
if (this != std::addressof(o))
copy_data_from(o);
return *this;
}
private:
void copy_data_from(Register const& o) {
Assert(_tranpoline_address);
// ...
}
static BYTE* allocate() {
return reinterpret_cast<BYTE*>(
VirtualAlloc(nullptr, _trampoline_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
);
}
BYTE* _trampoline_address;
static const/*expr*/ int _trampoline_size = 20;
};
只有一次调用allocate
,但我仍然将它放在static private
方法中,因为它很麻烦。
我还写了copy_data_from
,因为它会被使用两次(一次在copy-ctor中,一次在分配中)。
我个人很想让Register()
留下一个空的缓冲区,只在使用时填充。阅读函数必须检查nullptr
和allocate()
是否缺失:但无论如何都必须检查nullptr
。结果是一个更高效的move-ctor和move-assign,创建空数组(并在以后填充)效率更高等等。
在这种情况下,allocate()
变得更有用。您甚至可以ensure_allocated()
,如果_tranpoline_address
初始化nullptr
。