Joseph
Joseph

Reputation:

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

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

Upvotes: 58

Views: 15132

Answers (7)

Dewfy
Dewfy

Reputation: 23624

While most of the answers above focus on preventing the construction of the object (except for the excellent solution by @cmeerw), I would focus on the destructor to make the solution work in C++11 and above. When an object is destroyed on the stack, its destructor is simply invoked. However, when an object is allocated on the heap, an intermediate delete operator is needed. We can prevent compilation by making the destructor private, but still allow it to work by granting friendship to the delete operator.

class NonStackBase
{
    virtual ~NonStackBase() = default;
    friend void operator delete (void *) noexcept(noexcept(operator delete ((NonStackBase*)nullptr)));
public:
    NonStackBase() = default;
};

p.s. strange tail: noexcept(noexcept(operator delete ((NonStackBase*)nullptr))); just allows us probe signature of operator delete on presence of noexcept specification during compile-time.

Test time:

//NonStackBase b1; //fails on compile time
NonStackBase* b2 = new NonStackBase; //works good

Upvotes: 1

cmeerw
cmeerw

Reputation: 7356

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

Upvotes: 2

spiderlama
spiderlama

Reputation: 1685

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;

Upvotes: 7

NebulaFox
NebulaFox

Reputation: 8313

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

Upvotes: 26

user18476
user18476

Reputation: 39

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

Upvotes: -2

Dominik Grabiec
Dominik Grabiec

Reputation: 10655

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

Upvotes: 88

Jason Cohen
Jason Cohen

Reputation: 83021

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

Upvotes: 12

Related Questions