1Foo *ptr = new Foo;
,仅允许他们这样做:
1Foo myfooObject;
有人有什么想法吗?
干杯,尼克"/>

关于C#:如何防止在堆上创建对象?

关于C#:如何防止在堆上创建对象?

How to prevent an object being created on the heap?

有人知道如何在与平台无关的C代码中阻止在堆上创建对象吗?也就是说,对于类" Foo",我要阻止用户执行此操作:

1
Foo *ptr = new Foo;

,仅允许他们这样做:

1
Foo myfooObject;

有人有什么想法吗?

干杯,


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

1
2
3
4
5
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%的方法是唯一有关如何使用它的文档,并进行代码审查以确保正确使用它。


您可以为Foo重载new并将其设为私有。这意味着编译器会抱怨...除非您从Foo内部在堆上创建Foo实例。为了解决这种情况,您不能简单地编写Foo的新方法,然后链接器会抱怨未定义的符号。

1
2
3
4
class Foo {
private:
  void* operator new(size_t size);
};

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


我不知道如何可靠且便携地进行操作。...

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

我相信并非所有平台都在同一方向上实现其堆栈,因此,当应用程序开始验证堆栈增长的方式时,您可能需要进行一次一次性测试。

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

@尼克

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

例如:

1
2
3
4
5
struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

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


因为调试头可以覆盖操作员的新签名,所以最好将...签名用作完整的补救措施:

1
2
3
private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;

这可以通过将构造函数设为私有并提供静态成员以在堆栈中创建对象来防止

1
2
3
4
5
6
7
8
9
10
Class Foo
{
    private:
        Foo();
        Foo(Foo& );
    public:
        static Foo GenerateInstance() {
            Foo a ; return a;
        }
}

这将使对象的创建始终在堆栈中。


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


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

这是您想要的行为吗?


不确定这是否提供任何编译时机会,但是您是否考虑过为类重载'new'运算符?


推荐阅读