有人知道我如何在平台无关的C++代码中防止对象在堆上被创建吗?也就是说,对于一个类"Foo",我想要防止用户这样做:
Foo *ptr = new Foo;
并且只允许他们做这件事:
Foo myfooObject;
有没有人有任何想法?
谢谢,
有人知道我如何在平台无关的C++代码中防止对象在堆上被创建吗?也就是说,对于一个类"Foo",我想要防止用户这样做:
Foo *ptr = new Foo;
并且只允许他们做这件事:
Foo myfooObject;
有没有人有任何想法?
谢谢,
Nick的回答是一个不错的起点,但不完整,因为你实际上需要重载:
private:
void* operator new(size_t); // standard new
void* operator new(size_t, void*); // placement new
void* operator new[](size_t); // array new
void* operator new[](size_t, void*); // placement array new
(良好的编码实践应该建议您也重载delete和delete[]运算符--尽管我会这样做,但由于它们不会被调用,所以并不是真正必要的。)
Pauldoo 也正确指出,这种方法无法在Foo聚合时生效,虽然在从Foo继承时可以。您可以使用一些模板元编程魔术来帮助防止这种情况发生,但它不免受到"恶意用户"的影响,因此可能不值得增加复杂性。文档说明如何使用,以及代码审查以确保其正确使用,是唯一 ~100% 的方法。
::new
而不是new
来规避此问题,因为这将在全局范围内执行对operator new
的查找。 - Brian BiFoo
对象? - baltermia你可以对Foo重载new并将其设置为私有。这意味着编译器会抱怨...除非你正在从Foo中的堆上创建Foo的实例。为了捕捉这种情况,你可以简单地不编写Foo的new方法,然后链接器会抱怨未定义的符号。
class Foo {
private:
void* operator new(size_t size);
};
PS. 是的,我知道这可以很容易地被规避。我真的不推荐这样做 - 我认为这是一个坏主意 - 我只是在回答问题!;-)
FooClass::FooClass() {
char dummy;
ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
if (displacement > 10000 || displacement < -10000) {
throw "Not on the stack - maybe..";
}
}
this
指针可以指向堆栈(如果FooClass用作本地变量),也可以指向堆(如果FooClass分配在堆上或在堆上分配了一个类,则聚合)。 - pauldoodummy
错误地当成了一个成员变量... 抱歉。 - Vargas@Nick
这个问题可以通过创建一个从Foo派生或聚合的类来规避。我认为我所建议的方法(虽然不够健壮)仍然适用于派生和聚合类。
例如:
struct MyStruct {
Foo m_foo;
};
MyStruct* p = new MyStruct();
在堆上创建了一个 'Foo' 的实例,绕过了 Foo 的隐藏 new 操作符。
private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
这可以通过将构造函数设为私有并提供一个静态成员在堆栈中创建对象来防止。
Class Foo
{
private:
Foo();
Foo(Foo& );
public:
static Foo GenerateInstance() {
Foo a ; return a;
}
}
这将使对象的创建始终在堆栈中进行。
不确定这是否提供任何编译时机会,但您是否考虑过重载类的 'new' 运算符?