4

Basically what I want is:

class MyClass{
    public:
        MyClass() = default;
    // what should I do?
}

MyClass mc; // compile time error;
auto pmc = new MyClass; //OK
delete pmc; //OK too

I know I can make it heap-only by hiding constructor (can not new outside of the class now) or hiding destructor (can not delete outside of the class now) or hiding both. What if I don't want to introduce some new named function and just want the good old new and delete? Is it possible (even with hack)?

3
  • 4
    No, just write a function. Commented Oct 21, 2017 at 4:33
  • Please edit your question to explain why you want to forbid on-stack automatic variables of MyClass and give a more motivated example Commented Oct 21, 2017 at 4:43
  • I wish new operator were overloadable in such a way that it could return instances of the class, and could accept any number of arguments, just like constructors, so that we could write things like : auto px = new X(arg0, arg2, arg3); .... and delete be just like the destructor. Commented Oct 21, 2017 at 4:54

3 Answers 3

6

My "like a smart pointer, but not" idea:

#include <iostream>

class MyClass_ {
  private:
    /**/     MyClass_( void ) { }
    /**/    ~MyClass_( void ) { }
  public:
    void     func( void ) const { std::cout << "Hello" << std::endl; }

    friend class MyClass;
} ;

class MyClass {
  public:
    /**/     MyClass( void ) : p( new MyClass_ ) { }
    /**/    ~MyClass( void ) { delete p; }

    // Tricky implementation details follow...
    // The question in all cases is, who owns the MyClass_ that has been
    // allocated on the heap?  Do you always allocate a new one, and then
    // copy the guts?  (That might be expensive!)  Do you change ownership?
    // Then what about the other MyClass?  What does it point to?
    // Or do you share ownership?  Then you need to ref-count so you don't
    // delete too soon.  (And this whole thing turns into an ordinary
    // shared_ptr<MyClass_>)

    /**/     MyClass( const MyClass &o ) { }
    /**/     MyClass( MyClass &&o ) { }
    MyClass &operator=( const MyClass &o ) { }
    MyClass &operator=( MyClass &&o ) { }

    MyClass_ * operator->( void ) { return p; }
    const MyClass_ * operator->( void ) const { return p; }

  private:
    MyClass_ *p;
} ;

int
main( int, char ** )
{
    MyClass  a;                  // this will be destroyed properly
    MyClass *b = new MyClass;    // this will leak if you don't delete it

    a->func( );
    (*b)->func( );

    return 0;
}
5
  • 3
    This is pretty clever. It illustrates that the fact that the class can only live on the heap is actually nothing the user needs to be aware of. All they care about is instantiating an object. By hiding the heap allocation as an implementation detail, you can also preserve value semantics for the wrapper object if you want. Commented Oct 21, 2017 at 5:25
  • 1
    Either properly implement the Rule of Five, or include a comment that it needs to be done (or delete them). Otherwise, you will get undefined behavior when you copy the object.
    – Rakete1111
    Commented Oct 21, 2017 at 7:05
  • 1
    ^That. If you aren't going to write them, at least mention them
    – Passer By
    Commented Oct 21, 2017 at 8:01
  • My apologies; that was the last thing I was thinking about when I went to bed. I'm not current on c++-xxx, but let me see what I can do.
    – Dave M.
    Commented Oct 21, 2017 at 13:35
  • It's not that tricky in this case actually. One don't even need to consider the Rule of Five If all they want is move semantic (use a unique_ptr memeber) or reference semantic(use a shared_ptr memeber). They only need to consider those special member functions when they need value semantic (Even in these case, it can be abstract away by implementing a value_ptr. Of cause, the burden is still there).
    – J. Doe
    Commented Oct 22, 2017 at 1:56
0

This is going to sound like not-what-you-want, but surround it in another class. That way you can enforce your storage is allocated off of the heap, and keep such details away from your API user.

1
  • Can you provide code and clearer explanation... By surrounding, do you mean to make it a nested class? And how it would help?
    – Phil1970
    Commented Oct 21, 2017 at 4:36
0

A usual way would be to make your constructor private, and add some static member function (you could call it a factory or making function) which returns a pointer.

So your class would look like

class MyClass{
    private:
        MyClass() = default;
    public:
        static MyClass* make() { return new MyClass;  };
    // what should I do?
}

and you'll code:

 auto mc = MyClass::make();

elsewhere (instead of new MyClass)

etc. However be aware of the rule of five and consider using (as return type of your MyClass::make) some smart pointer from the <memory> header.

You could also define your own smart pointer class with its own unary operator -> and operator * and your own variadic templates inspired by std::make_shared ...

just want the good old new and delete

In genuine C++11, this is frowned upon and may be considered bad style. You should avoid using explicitly new outside of your library, and adopt some smart pointer way of coding.

1
  • You could use the smart pointer idea, but instead of reference-counting the object, you're just using the pointer to ensure that all the underlying objects are allocated on the heap. (The pointer itself could be allocated or automatic, it doesn't matter too much.)
    – Dave M.
    Commented Oct 21, 2017 at 4:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.