如何防止在堆上创建对象?

时间:2020-03-05 18:39:37  来源:igfitidea点击:

有谁知道我能用平台无关的C ++代码阻止在堆上创建对象吗?也就是说,对于" Foo"类,我想阻止用户这样做:

Foo *ptr = new Foo;

并且只允许他们这样做:

Foo myfooObject;

有人有什么想法吗?

干杯,

解决方案

回答

我们可以在Foo类中声明一个名为" operator new"的函数,该函数将阻止对常规形式的new的访问。

这是我们想要的行为吗?

回答

我们可以为Foo重载new并将其设为私有。这意味着编译器会抱怨...除非我们要在Foo中的堆上创建Foo实例。为了解决这种情况,我们根本无法编写Foo的新方法,然后链接器会抱怨未定义的符号。

class Foo {
private:
  void* operator new(size_t size);
};

PS。是的,我知道这很容易解决。我真的不建议这样做,我认为这是一个坏主意,我只是在回答这个问题! ;-)

回答

不知道这是否提供了编译时的机会,但是我们是否考虑过为类重载" new"运算符?

回答

我不知道如何可靠地以便携式方式进行操作。

如果对象在堆栈上,则可以在构造函数中断言" this"的值始终接近堆栈指针。在这种情况下,对象很有可能会在堆栈上。

我相信并非所有平台都以相同的方向实现其堆栈,因此我们可能希望在应用开始验证堆栈增长的方式时进行一次一次性测试。

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}

回答

@缺口

通过创建从Foo派生或者聚合的类可以避免这种情况。我认为我所建议的(虽然不够健壮)仍然适用于派生类和聚合类。

例如:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

在这里,我绕过Foo隐藏的new运算符在堆上创建了一个'Foo'实例。

回答

我们可以将其声明为接口,并直接从我们自己的代码中控制实现类。

回答

尼克的答案是一个很好的起点,但并不完整,因为我们实际上需要重载:

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%的方式是有关如何使用它的文档以及对代码进行回顾以确保其正确使用的方法。