提问人:Kevin 提问时间:9/24/2008 更新时间:10/10/2020 访问量:10896
如何防止通过“new”运算符分配类?(我想确保我的 RAII 类始终在堆栈上分配。
How do I prevent a class from being allocated via the 'new' operator? (I'd like to ensure my RAII class is always allocated on the stack.)
答:
60赞
6 revs, 4 users 67%Kevin
#1
您需要做的就是将类的新运算符声明为 private:
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
// ...
};
将“运算符 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;
};
相关问题:是否可以阻止对象的堆栈分配,只允许它使用“new”来启动?
评论
3赞
Richard Corden
9/24/2008
另一点是,这只会阻止从类层次结构外部调用“new”。即。“X”的成员可以调用函数。新的 C++ '0x 功能“=delete”将允许您显式停止调用该函数。
6赞
Konrad Rudolph
9/24/2008
Richard,不,这些方法永远不能被调用,因为它们只是声明的,而不是定义的。不同之处在于,专用访问将产生链接器错误,而不是编译器错误。
4赞
Chris Dodd
11/23/2016
这并不能阻止 ,它显式调用全局运算符 new,而不是类运算符 new...X *x = ::new X;
0赞
Dave Ruske
4/27/2017
至少有一个原因可以解释为什么最好给予朋友私人访问权限:它可能会阻止他们出现在 IDE 的代码完成中。static void *operator new (size_t) = delete
7赞
DrPizza
9/24/2008
#2
我不相信你的动机。
在免费商店中创建 RAII 类是有充分理由的。
例如,我有一个 RAII 锁类。我有一条通过代码的路径,其中只有在某些条件成立时才需要锁(它是一个视频播放器,如果我加载并播放了视频,我只需要在渲染循环期间按住锁;如果没有加载任何内容,我不需要它)。因此,在自由存储上创建锁(使用 )的能力非常有用;它允许我使用相同的代码路径,无论我是否必须取出锁。unique_ptr
即像这样的东西:
unique_ptr<lock> l;
if(needs_lock)
{
l.reset(new lock(mtx));
}
render();
如果我只能在堆栈上创建锁,我就做不到......
评论
0赞
Kevin
9/24/2008
一个有趣的观点。为此,我给你+1。但请注意,在某些情况下,RAII 习语不一定是可选的。无论如何,也许解决困境的更好方法是向锁构造函数添加一个参数,以指示是否需要锁。
0赞
Kevin
9/24/2008
例如: class lock { mutex& m; bool dolock; public: lock(mutex& m_, bool dolock_) : m(m_), dolock(dolock_) { if (dolock) m.lock(); } ~lock() { if (dolock) m.unlock();然后你可以写:lock l(mtx, needs_lock);render();
0赞
Thomas
4/21/2013
防止是必不可少的情况:如果您的 RAII 类在内部维护该类的所有活动对象的静态堆栈,并假定该类的对象以创建它们的相反顺序被销毁。我用它来维护 OpenGL 状态,作为已弃用的 / 函数的替代品。new
glPushAttrib
glPopAttrib
2赞
Kevin
9/24/2008
#3
@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();
0赞
DrPizza
9/24/2008
#4
在我的特殊情况下,如果锁不是必需的,互斥锁甚至不存在,所以我认为这种方法会更难适应。
我想我真正难以理解的是禁止在免费商店中创建这些对象的理由。
评论
1赞
Kevin
9/24/2008
理由是,这只是一种帮助执行规则的方法,这样下一个开发人员就不会意外地做一些事情,比如忘记删除锁(这会导致锁定)。
上一个:强制某些运营商成为成员的理由
下一个:什么是 C 语言中的引用?
评论