views:

184

answers:

5

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?

+9  A: 

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
-1 for "If it's private, the compiler must not generate that code, ..."
Berkus
@Berkus: Pardon me?
sbi
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
@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
@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
Thanks sbi. We use smart pointers for all our shared objects, but it's definitely worth noting.
eladidan
Ehm, we have some sort of textual misunderstanding here. Since english is not my natural language, I won't dive into this debate.
Berkus
@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
Dan
@sbi I believe this IS the root of my confusion. Sorry about that!
Berkus
+1  A: 

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

Berkus
+12  A: 

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
+1 - instead of messing with private destructors using a variation of the singleton pattern is the way to go
Holger Kretzschmar
@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
+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
+1 will play better with most auto pointers than the original.
Pete Kirkham
@sbi: I wish I could do that too.
DeadMG
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
+1  A: 

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
+1  A: 

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
This should be a comment (you do not answer the (main) question at all). Same for Pardeep above.
n1ck
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
@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.
n1ck
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