我应该外包分配算法吗? (RAII)

时间:2015-05-20 17:06:41

标签: c++ memory-management raii

现在我的班级有一个构造函数复制构造函数复制赋值运算符,其中首先执行相同的操作< / 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个函数中分配内存的正确解决方案是什么?

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)

你可以做以下两件事之一:

  1. 创建一个dependencies { compile project(':Lib-AndroidLibrary') } 函数,然后在每个构造函数中调用它。这仍然允许类的其他成员函数在构造之后调用函数,但这应该没问题(只是不要调用它!)。 子类无法调用类的私有成员,因此您应该没问题。
  2. 使用delegated constructors。在一个构造函数中执行分配,然后从其他构造函数中调用该构造函数。显然,没有人可以明确地调用构造函数,因此应该关注您的问题。可能需要注意的是:您需要使用符合C ++ 11的编译器。

答案 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()留下一个空的缓冲区,只在使用时填充。阅读函数必须检查nullptrallocate()是否缺失:但无论如何都必须检查nullptr。结果是一个更高效的move-ctor和move-assign,创建空数组(并在以后填充)效率更高等等。

在这种情况下,allocate()变得更有用。您甚至可以ensure_allocated(),如果_tranpoline_address初始化nullptr