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

时间:2008-08-14 13:19:08

标签: c++ stack heap

在平台无关的C ++代码中是否有人知道我怎么能阻止在堆上创建对象?也就是说,对于“Foo”类,我想阻止用户这样做:

Foo *ptr = new Foo;

并且只允许他们这样做:

Foo myfooObject;

有没有人有任何想法?

干杯,

9 个答案:

答案 0 :(得分:24)

Nick's answer是一个很好的起点,但不完整,因为你实际上需要重载:

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%方法。

答案 1 :(得分:9)

您可以为Foo重载新内容并将其设为私有。这意味着编译器会呻吟......除非你在Foo中在堆上创建一个Foo实例。要抓住这种情况,您可能根本就不会编写Foo的新方法,然后链接器会抱怨未定义的符号。

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

PS。是的,我知道这很容易被规避。我真的不推荐它 - 我认为这是一个坏主意 - 我只是在回答这个问题! ; - )

答案 2 :(得分:7)

我不知道如何以可移植的方式可靠地做到这一点......但是......

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

我相信并非所有平台都在同一个方向上实现堆栈,因此当应用程序开始验证堆栈增长方式时,您可能希望进行一次性测试。或者做一些软糖:

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

答案 3 :(得分:3)

@Nick

这可以通过创建派生或聚合Foo的类来规避。我认为我的建议(虽然不健壮)仍然适用于派生和聚合类。

E.g:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

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

答案 4 :(得分:2)

因为调试头可以覆盖运算符的新签名,所以最好使用...签名作为完整的补救措施:

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

答案 5 :(得分:0)

你可以在Foo类中声明一个名为“operator new”的函数,它会阻止对new的正常形式的访问。

这是你想要的那种行为吗?

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

Class Foo
{
    private:
        Foo();
        Foo(Foo& );
    public:
        static Foo GenerateInstance() { 
            Foo a ; return a; 
        }
}

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

答案 8 :(得分:-1)

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