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

C++C++ Faq

C++ Problem Overview


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

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

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

Solution 3 - C++

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

Solution 4 - C++

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;

Solution 5 - C++

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).

Solution 6 - C++

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJosephView Question on Stackoverflow
Solution 1 - C++DaeminView Answer on Stackoverflow
Solution 2 - C++NebulaFoxView Answer on Stackoverflow
Solution 3 - C++Jason CohenView Answer on Stackoverflow
Solution 4 - C++spiderlamaView Answer on Stackoverflow
Solution 5 - C++cmeerwView Answer on Stackoverflow
Solution 6 - C++user18476View Answer on Stackoverflow