我正在实现一个采用RAII惯用语法的类。显然,这个类只能在堆栈上实例化,因此我正在寻找一种方法来强制执行。
我的问题是,这样做是否会有任何不容易看出的副作用?
这是否是在堆栈上实例化的好方法?
是否存在任何可移植性问题?
谢谢你的帮助!
编辑:
我的RAII类只是实例化我正在工作的框架的各个部分,因此对于该类没有其他可行的操作,除了在堆栈上创建一个实例。
目标只是提供一种简单的可能性来配置框架并将其置于可用状态,而无需在客户端代码中实例化10个对象。
这个类显然只能在堆栈上实例化,所以我正在寻找一种强制执行的方法。
如果你必须强制执行,那么对用户来说显然并不明显...
主要的缺点是它无法工作。
即使新的操作符是私有的,用户仍然可以意外地将您的类用作其自己类的数据成员或基类,然后使用new
实例化他们的类。这会阻止他们编写Foo *f = new Foo();
,而应该编写Foo f;
,但它并不能强制执行他们对RAII类的使用与词法范围匹配,这可能是您真正想要强制执行的内容。
如果有人想要使用具有动态存储期的锁(或其他东西),那么他们要么非常聪明,要么非常愚蠢。无论哪种情况,如果您让他们自己创建,则无法阻止他们绕过您的限制。
您可以将所有构造函数设置为私有(包括复制构造函数),然后提供一个友元函数按值返回。他们必须编写:
const Foo &f = GimmeAFoo();
标准要求扩展返回值的生命周期,只要f
的范围。由于它们无法复制对象,因此无法使值逃离引用的范围。由于它们无法初始化数据成员或基类,因此无法使用解决方法。请注意,它们必须取一个const引用,所以如果您的类需要非const成员,则实际上不起作用。
他们仍然可以做一些愚蠢的事情,比如像这样初始化自己类的const引用数据成员,但是对象本身不会逃离发生这种情况的范围。他们将得到一个悬空引用,就像他们如果获取了指向不应该的东西的指针一样。
void example() {
shared_ptr<T> p (new T());
// No RAII violation, still uses operator new.
vector<T> v (some_initial_size);
// No RAII violation, still uses operator new (the placement form is used
// inside the default allocator).
}
在栈上实例化是一个好的方法吗?
你想要防止什么?使用场景是什么?任何使用new操作符创建你的类型的人,要么1)知道他们在做什么并且需要它,要么2)无论你怎么做都会糟糕地管理资源。试图强制执行这个规则只会妨碍那些在#1中的人,而不会帮助那些在#2中的人。
这是另一种表述Steve所说的话:
这个类显然只能在栈上实例化,所以我正在寻找一种强制执行这种规则的方法。
如果这是显而易见的,为什么还需要强制执行?
如果用户会盲目使用 "new T()",那么你认为他们不会盲目使用 "::new T()" 吗?
目标只是提供一个简单的方式来配置框架,并将其置于可用状态,而不必在客户端代码中实例化10个对象。
#include <framework>
int main() {
framework::Init init;
// Do stuff.
}