Is it possible to prevent stack allocation of an object and only allow it to be instantiated with 'new'?
Asked Answered
S

6

57

Is it possible to prevent stack allocation of an object and only allow it to be instiated with 'new' on the heap?

Stylize answered 24/9, 2008 at 1:27 Comment(1)
The reverse, which may also be interesting to readers: #11485Listing
A
88

One way you could do this would be to make the constructors private and only allow construction through a static method that returns a pointer. For example:

class Foo
{
public:
    ~Foo();
    static Foo* createFoo()
    {
        return new Foo();
    }
private:
    Foo();
    Foo(const Foo&);
    Foo& operator=(const Foo&);
};
Astound answered 24/9, 2008 at 1:32 Comment(4)
Or better still a static function that returns a std::unique_ptr<Foo>.Arte
Related question: How do I prevent a class from being allocated via the 'new' operator? (I'd like to ensure my RAII class is always allocated on the stack.)Hemorrhage
But why make it unassignable too?Gertrudegertrudis
Because if it's heap allocated then the object should not be copied, only its pointer should be copied.Astound
M
26

In the case of C++11

class Foo
{
  public:
    ~Foo();
    static Foo* createFoo()
    {
        return new Foo();
    }

    Foo(const Foo &) = delete; // if needed, put as private
    Foo & operator=(const Foo &) = delete; // if needed, put as private
    Foo(Foo &&) = delete; // if needed, put as private
    Foo & operator=(Foo &&) = delete; // if needed, put as private

  private:
    Foo();
};
Menstruate answered 2/10, 2012 at 20:7 Comment(3)
As Scott Meyers stated in "Item 11: Prefer deleted functions to private undefined ones." his book "Effective Modern C++", it's better to declare deleted member functions public. --QUOTE-- "By convention, deleted functions are declared public, not private. There’s a reason for that. When client code tries to use a member function, C + + checks accessibility before deleted status. When client code tries to use a deleted private function, some compilers complain only about the function being private, even though the function’s accessibility doesn’t really affect whether it can be used."Quincyquindecagon
--QUOTE-- "It’s worth bearing this in mind when revising legacy code to replace private-and-not-defined member functions with deleted ones, because making the new functions public will generally result in better error messages."Quincyquindecagon
Must. Give. Moar. Up. Votes.Listing
E
12

You could make the constructor private, then provide a public static factory method to create the objects.

Enciso answered 24/9, 2008 at 1:31 Comment(0)
C
6

The following allows public constructors and will stop stack allocations by throwing at runtime. Note thread_local is a C++11 keyword.

class NoStackBase {
    static thread_local bool _heap;
protected:
    NoStackBase() {
        bool _stack = _heap;
        _heap = false;
        if (_stack)
            throw std::logic_error("heap allocations only");
    }
public:
    void* operator new(size_t size) throw (std::bad_alloc) { 
        _heap = true;
        return ::operator new(size);
    }
    void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw () {
        _heap = true;
        return ::operator new(size, nothrow_value);
    }
    void* operator new(size_t size, void* ptr) throw () {
        _heap = true;
        return ::operator new(size, ptr);
    }
    void* operator new[](size_t size) throw (std::bad_alloc) {
        _heap = true;
        return ::operator new[](size);
    }
    void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw () {
        _heap = true;
        return ::operator new[](size, nothrow_value);
    }
    void* operator new[](size_t size, void* ptr) throw () {
        _heap = true;
        return ::operator new[](size, ptr);
    }
};

bool thread_local NoStackBase::_heap = false;
Chyou answered 20/11, 2013 at 2:59 Comment(3)
I don't think you need _stack as a data member. Having it as a simple stack variable inside the NoStackBase constructor should do.Jointer
You also don't need to make the destructor virtual. Nobody can delete a derived class via a NoStackBase anyway.Jointer
since you explicitly call global operator new, I assume this won't call any custom operator overload those objects have defined (?), and forcing the use of those may be the motivating reason for this questionConsistent
B
2

This should be possible in C++20 using a destroying operator delete, see p0722r3.

#include <new>

class C
{
private:
  ~C() = default;
public:
  void operator delete(C *c, std::destroying_delete_t)
  {
    c->~C();
    ::operator delete(c);
  }
};

Note that the private destructor prevents it from being used for anything else than dynamic storage duration. But the destroying operator delete allows it to be destroyed via a delete expression (as the delete expression does not implicitly call the destructor in this case).

Botulism answered 22/8, 2018 at 17:14 Comment(0)
I
-2

You could create a header file that provides an abstract interface for the object, and factory functions that return pointers to objects created on the heap.

// Header file

class IAbstract
{
    virtual void AbstractMethod() = 0;

public:
    virtual ~IAbstract();
};

IAbstract* CreateSubClassA();
IAbstract* CreateSubClassB();

// Source file

class SubClassA : public IAbstract
{
    void AbstractMethod() {}
};

class SubClassB : public IAbstract
{
    void AbstractMethod() {}
};

IAbstract* CreateSubClassA()
{
    return new SubClassA;
}

IAbstract* CreateSubClassB()
{
    return new SubClassB;
}
Impervious answered 24/9, 2008 at 1:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.