How 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 instantiated with 'new'?

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

How to prevent an object being created on the heap?

Nick's answer is a good starting point, but incomplete, as you actually need to overload:

private:
void* operator new(size_t); // standard new
void* operator new(size_t, void*); // placement new
void* operator new[](size_t); // array new
void* operator new[](size_t, void*); // placement array new

(Good coding practice would suggest you should also overload the delete and delete[] operators -- I would, but since they're not going to get called it isn't really necessary.)

Pauldoo is also correct that this doesn't survive aggregating on Foo, although it does survive inheriting from Foo. You could do some template meta-programming magic to HELP prevent this, but it would not be immune to "evil users" and thus is probably not worth the complication. Documentation of how it should be used, and code review to ensure it is used properly, are the only ~100% way.

Why not always instantiate objects on the stack? C++

You can certainly do this for some programs under some circumstances. Just for example, back in the depths of time, Fortran was defined so all the data used by a program could be allocated statically (and it pretty routinely was).

At the same time, it is quite limiting and problematic. Just for a few examples, it rules out (almost) all recursion, which can be really handy for working with some types of recursive data structures (e.g., trees).

It also means that all your variables become essentially globals, so (for example) any code in the program can read and/or write almost any variable in the program. Experience with languages like Fortran and (early versions of) BASIC that used this model indicates that it requires substantial discipline to develop what's currently seen as a small- to medium-sized program, and and developing what's now typically seen as a large system is probably next to impossible. Dependencies between different parts of the code become so complex so quickly that it becomes nearly impossible to determine what's used where, what parts depend upon what others, etc.

I doubt this can be justified in practice. The overhead of allocating stack space starts out so minuscule that eliminating it simply won't improve speed by any noticeable degree. In fact, it may easily do exactly the opposite. Pre-allocating your variables means that each will (pretty much of necessity) live in a unique part of memory. A relatively large percentage of them will be to parts of memory that aren't currently in the cache at a given time, so you'll end up with poor locality of reference leading to poor cache usage.

Allocating local data when you enter a function means that most of your variables live at or close to the top of the stack. Since you're using the memory near the top of the stack almost constantly, that memory stays in the cache most of the time, so nearly all your memory accesses hit the cache.

The time taken for allocations is typically (well) under 1%, but the penalty for accessing main memory instead of the cache is typically at least 10x, and often much higher (20-50x is pretty common). Your mileage will vary depending on data access patterns, but you have a huge potential for a large loss, and (at best) only a small chance of a tiny gain.

Summary: this is a lousy idea. It's much more likely to do a lot of harm than even a tiny bit of good.

How to prevent others create a new instance of a class on heap?

I think the best you can do is to declare a private operator new (I can't recall if this is needed but you'll probably want to do all three: normal, array, and placement) in your base class. The user can still get around this by creating their own operator new in the Derived class but at least they have to think about it and actively work to subvert your intention.

If you're worried about non-accidental problems with creating your class on the heap (for example malicious developers of child classes), C++ is not the language for this project. It's powerful and has lots of places where your have to rely on your end-programmers not bypassing the intentions.

Allow objects to be allocated only using dynamic allocation

// Dynamic.h
class OnlyDynamic
{
template<class T> friend struct Dynamic;
virtual void*** __Restriction () = 0;
};

template<class T>
class Dynamic : public T
{
virtual void*** __Restriction () { return 0; }
~Dynamic();
public:
#ifdef Cpp0x
template<typename... Args>
Dynamic(Args... args) : T(args...) {}
#else
Dynamic () {}
template<typename A1> Dynamic(const A1 &a1) : T(a1) {}
template<typename A1, typename A2> Dynamic(const A1 &a1, const A2 &a2) : T(a1,a2) {}
//...
template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
Dynamic(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5, const A6 &a6) : T(a1,a2,a3,a4,a5,a6) {}
#endif
};

Usage:


Suppose, I want to make class X only dynamically allocatable; I should simply derive OnlyDynamic (access specifier doesn't matter) and allocate with new Dynamic<X>().

Example:

class Base {};

struct A : Base, OnlyDynamic // <-- only inherit
{
A (int i) {}
};

A *p = new Dynamic<A>(3);
delete p;

As of now, I am seeing all the given requirements getting fulfilled with this solution.

C++ - Prevent global instantiation?

Instead of placing somewhat arbitrary restrictions on objects of your class I'd rather make the calls to the C API safe by wrapping them into a class. The constructor of that class would do the initialization and the destructor would release acquired resources.

Then you can require this class as an argument to your class and initialization is always going to work out.

The technique used for the wrapper is called RAII and you can read more about it in this SO question and this wiki page. It originally was meant to combine encapsulate resource initialization and release into objects, but can also be used for a variety of other things.

How to prohibit the construction of object?

One option would be to give the class a pure virtual function, and mark it final:

struct A final
{
virtual void nonconstructible() = 0;
};

[Live example]



Related Topics



Leave a reply



Submit