10

I know there are methods to prevent a class from being created on the heap, by preventing the user from using the new and delete operator. I am trying to do just the opposite. I have a class that I want to prevent the user from creating an instance of it on the stack, and that only instances instigated using the new operator will compile. More specifically, I want the following code to receive an error during compilation:

MyClass c1; //compilation error

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

From searching the web, I found this suggestion on how to do it:

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();
}

What I don't understand is why this should work. Why would the destructor be called while creating an instance of MyClass?

IndustProg
  • 627
  • 1
  • 13
  • 33
eladidan
  • 2,634
  • 2
  • 26
  • 39
  • 4
    by the way calling destrory() like this will give you a compiler error as well since it is declared private – codencandy Jun 22 '10 at 10:36
  • 3
    I would be interested to know why you want this ? – log0 Jun 22 '10 at 10:41
  • 1
    see my other question, which explains it thoroughly: http://stackoverflow.com/questions/3095856/preventing-unaligned-data-on-the-heap – eladidan Jun 22 '10 at 18:16

5 Answers5

25

When myclass reaches the end of its scope (the next }) the compiler calls the destructor to free it from the stack. If the destructor is private, however, then the destructor cannot be accessed, so the class cannot be placed on the stack.

I don't like the look of delete this. In general I think objects should not destroy themselves. Perhaps a better way is to have a private constructor for your class then use a static function to create an instance.

// 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
AshleysBrain
  • 22,335
  • 15
  • 88
  • 124
  • 1
    +1 - instead of messing with private destructors using a variation of the singleton pattern is the way to go – codencandy Jun 22 '10 at 10:34
  • 19
    @Holger: The one and only purpose of a singleton is to allow _only one_ instance, and this doesn't do this, so __it is not a singleton at all.__ _I wish I could down-vote comments._ – sbi Jun 22 '10 at 10:40
  • +1 Good one, using a factory method instead of hacking up something that might not be so obvious to someone who has to use your code. – fingerprint211b Jun 22 '10 at 11:13
  • +1 will play better with most auto pointers than the original. – Pete Kirkham Jun 22 '10 at 11:58
  • 1
    @sbi: I wish I could do that too. – Puppy Jun 22 '10 at 12:36
  • good. It definitely comes more naturally to the user who has to use this class. Thanks for the explanation as to why the private dtor approach would work too – eladidan Jun 22 '10 at 18:19
12

Why would the destructor be called while creating an instance of MyClass?

It isn't. It must be invoked automatically when the instance goes out of scope, though. If it's private, the compiler must not generate that code, hence the error.

If you think making the destructor private is obscure, another way to restrict a class to dynamic allocation is to make all the constructors private and only have MyClass::create() functions returning dynamically allocated objects:

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

Note that returning naked pointers to objects that must be deleted is frowned upon. You should return smart pointers instead:

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);}
  // ...
};
sbi
  • 219,715
  • 46
  • 258
  • 445
  • 1
    -1 for "If it's private, the compiler must not generate that code, ..." – berkus Jun 22 '10 at 11:50
  • If it's private, it can be called from inside class scope only. It doesn't mean compiler must or must not generate code. – berkus Jun 22 '10 at 11:53
  • 1
    @Berkus: Privacy is only a feature of the compiler's front-end. Nothing but the rule encoded into it to not to allow access would hinder a compiler to generate code to access private data. You can see this when you `#define private public` before including a class which you only have as object files (in a lib, usually): While technically invoking undefined behavior, most compilers will happily generate code that accesses private data in that class. Technically this isn't a problem, so _the only reason compilers don't allow access to privates is because they must not_. – sbi Jun 22 '10 at 12:09
  • 2
    @Berkus: "If it's declared private, the compiler must not generate that code." is absolutely correct, although over-specific. Better would be, "If it's declared, the compiler must not generate that code, the programmer is claiming the privilege of writing it himself." C++0x fixes this with defaulted member functions. – Ben Voigt Jun 22 '10 at 12:50
  • Thanks sbi. We use smart pointers for all our shared objects, but it's definitely worth noting. – eladidan Jun 22 '10 at 18:23
  • Ehm, we have some sort of textual misunderstanding here. Since english is not my natural language, I won't dive into this debate. – berkus Jun 22 '10 at 23:05
  • @Berkus: In my language "you must not" would mean "you don't have to". In English, however, it means "you are not allowed to". Could that be the root of the confusion? – sbi Jun 23 '10 at 07:57
  • @sbi: regarding "must not" -- exactly right. When I learned German (as a native English speaker), knowing when to use *duerfen* vs. *muessen* in the negative, it took me a while to get it right. Kudos to you & Berkus for conversing in a non-native language. – Dan Jun 25 '10 at 14:39
  • @sbi I believe this IS the root of my confusion. Sorry about that! – berkus Jun 27 '10 at 22:47
1

Because when instance goes out of scope, it has to be destructed using destructor. Pointer to instance does not do this.

berkus
  • 1,552
  • 12
  • 16
1

Whenever a local variable goes out of scope, it is destroyed. And on destruction, destructor of object is called. Here, scope is of main function. When program exits, myclass object's destructor will be called

Pardeep
  • 929
  • 6
  • 14
1

It isn't. The compiler is trying to call the destructor when it goes out of scope, and is indicating to the line of code that produces this effect, which is much more useful than pointing at the end of the function.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • This should be a comment (you do not answer the (main) question at all). Same for Pardeep above. – n1ckp Jun 22 '10 at 11:07
  • 1
    Question was "Why would the destructor be called while creating an instance of MyClass?". This is an answer to that question. Learn to read first. – berkus Jun 22 '10 at 11:51
  • 1
    @Berkus huh? The question in the title is "C++, preventing class instance from being created on the stack (during compilation)". Sorry but this DO NOT answer that question. – n1ckp Jun 22 '10 at 12:04
  • The title of the question is not the question itself. The question is a sentence or a paragraph that ends with a question sign. – berkus Jun 22 '10 at 23:02