Reputation:
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
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
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
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
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
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
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
Reputation: 83021
You could make the constructor private
, then provide a public
static factory method to create the objects.
Upvotes: 12