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

Should I outsource allocation algorithm? (RAII)

本文关键字:算法 raii 分配 包分配 我应该      更新时间:2023-10-16

现在,我的课程具有构造函数复制构造函数 and 复制分配分配操作员 when首先在(分配内存)上做同样的事情。破坏者正在处理内存。

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个函数中的内存的正确解决方案是什么?

您可以创建一个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;
}
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。结果是一个更有效的移动和移动分配,创建空数组(稍后填充)的效率要高得多,等等。

在这种情况下, allocate()事实更有用。您甚至可以拥有ensure_allocated(),如果nullptr

初始化_tranpoline_address

您可以做两件事之一:

  1. 创建一个private函数,然后在每个构造函数中调用它。这仍然允许班级的其他成员功能在施工后调用该功能,但这应该是可以的(只是不称呼它!)。子类无法致电班级的私人成员,所以您应该没事的。
  2. 使用授权的构造函数。在一个构造函数中执行分配,然后从其他构造函数中调用该构造函数。显然,没有人可以明确称呼构造函数,因此应该关心您的担忧。可能的警告:您需要使用C 11符合编译器。