C ++,阻止在堆栈上创建类实例(在编译期间)

时间:2010-06-22 10:25:45

标签: c++ class-design

我知道有一些方法可以防止用户使用newdelete运算符来阻止在堆上创建类。我正试图做相反的事情。我有一个类,我想阻止用户在堆栈上创建它的实例,并且只有使用new运算符发起的实例才会编译。更具体地说,我希望以下代码在编译期间收到错误:

MyClass c1; //compilation error

MyClass* c1 = new MyClass(); //compiles okay

通过搜索网络,我发现了如何做到这一点的建议:

class MyClass {
public:
    MyClass();
private:
    void destroy() const { delete this; }

...

private:
    ~MyClass();
};

int main(int argc,char** argv)
{
    MyClass myclass; // <--- error, private destructor called here !!!

    MyClass* myclass_ptr = new MyClass;
    myclass_ptr->destroy();
}

我不明白为什么这应该有效。为什么在创建MyClass的实例时会调用析构函数?

5 个答案:

答案 0 :(得分:23)

myclass到达其范围的末尾(下一个})时,编译器会调用析构函数将其从堆栈中释放出来。但是,如果析构函数是私有的,则无法访问析构函数,因此无法将类放在堆栈中。

我不喜欢delete this的样子。总的来说,我认为对象不应该破坏自己。也许更好的方法是为您的类创建一个私有构造函数,然后使用静态函数创建一个实例。

// In class declaration...
static MyClass* Create()
{
    return new MyClass(); // can access private constructor
}

// ...

MyClass myclass; // illegal, cannot access private constructor

MyClass* pMyClass = MyClass::Create();
delete pMyClass; // after usage

答案 1 :(得分:12)

  

为什么在创建MyClass的实例时会调用析构函数?

不是。但是,当实例超出范围时,必须自动调用它。如果它是私有的,编译器必须不生成该代码,因此错误。

如果您认为将析构函数设为私有,则将类限制为动态分配的另一种方法是将所有构造函数设为私有,并且只有MyClass::create()函数返回动态分配的对象:

class MyClass {
public:
  static MyClass* create()             {return new MyClass();}
  static MyClass* create(const Foo& f) {return new MyClass(f);}
private:
  MyClass();
  MyClass(const Foo&);
};

请注意,将裸指针返回到必须删除的对象是不受欢迎的。你应该返回智能指针:

class MyClass {
public:
  static std::shared_ptr<MyClass> create()             {return new MyClass();}
  static std::shared_ptr<MyClass> create(const Foo& f) {return new MyClass(f);}
  // ...
};

答案 2 :(得分:1)

因为当实例超出范围时,必须使用析构函数对其进行破坏。指向实例的指针不会这样做。

答案 3 :(得分:1)

每当局部变量超出范围时,它就会被销毁。 在破坏时,对象的析构函数被调用。这里,范围是主要功能。当程序退出时,将调用myclass对象的析构函数

答案 4 :(得分:1)

不是。编译器在超出范围时尝试调用析构函数,并指示产生此效果的代码行,这比指向函数末尾更有用。