我想确保我的 RAII 类始终分配在堆栈上。
如何防止通过“新”运算符分配类?
您需要做的就是将类的新运算符声明为私有:
class X
{
private:
// Prevent heap allocation
void * operator new (size_t);
void * operator new[] (size_t);
void operator delete (void *);
void operator delete[] (void*);
// ...
// The rest of the implementation for X
// ...
};
将“operator new”设为私有可以有效地防止类外的代码使用“new”来创建 X 的实例。
要完成这些操作,您应该隐藏“运算符删除”和两个运算符的数组版本。
从 C++11 开始,您还可以显式删除函数:
class X
{
// public, protected, private ... does not matter
static void *operator new (size_t) = delete;
static void *operator new[] (size_t) = delete;
static void operator delete (void*) = delete;
static void operator delete[](void*) = delete;
};
我不相信你的动机。
在免费商店创建 RAII 课程有充分的理由。
例如,我有一个 RAII 锁类。我有一条通过代码的路径,其中只有在某些条件成立时才需要锁定(它是一个视频播放器,如果我已经加载并播放了视频,我只需要在渲染循环期间保持锁定;如果没有加载,我不需要它)。因此,在免费存储上创建锁(使用unique_ptr
)的能力非常有用;它允许我使用相同的代码路径,无论我是否必须取出锁。
即是这样的:
unique_ptr<lock> l;
if(needs_lock)
{
l.reset(new lock(mtx));
}
render();
如果我只能在堆栈上创建锁,我就做不到......
@DrPizza:
你有一个有趣的观点。请注意,在某些情况下,RAII 习语不一定是可选的。
无论如何,解决您的困境的更好方法可能是向您的锁构造函数添加一个参数,指示是否需要锁。例如:
class optional_lock
{
mutex& m;
bool dolock;
public:
optional_lock(mutex& m_, bool dolock_)
: m(m_)
, dolock(dolock_)
{
if (dolock) m.lock();
}
~optional_lock()
{
if (dolock) m.unlock();
}
};
然后你可以写:
optional_lock l(mtx, needs_lock);
render();
在我的特殊情况下,如果不需要锁,则互斥锁甚至都不存在,所以我认为这种方法更难适应。
我想我真正难以理解的是禁止在免费商店中创建这些对象的理由。