views:

512

answers:

5

I have a number of classes that I would like to explicitly disallow heap allocation for. It occurred to me this weekend that I could just declare operator new private (and unimplemented)... Sure enough, this results in compile errors when you attempt to new the class... My question is: Is there more to this? Am I missing something or is this a good way of doing what I want?

#include <stdio.h>

class NotOnTheHeap
{
public:
  NotOnTheHeap() : foo( 0 )
  {
  }

private:
  void *operator new( size_t );
  void operator delete( void* );
  void *operator new[]( size_t );
  void operator delete[]( void* );

  int foo;
};

class Heapable
{
private:
  NotOnTheHeap noth;
};

int main( int argc, char* argv[] )
{
  NotOnTheHeap noth;

  Heapable* heapable = new Heapable;

  return 0;
}
A: 

Can't you just make the implementation of operator new an assert(0)?

dsimcha
I think a compile time error is better than allowing the code to actually compile then die at runtime.
Martin York
Compile errors are better than asserts.
dicroce
To be a bit more precise, this is a link time error (which is still preferable to a run time error).
R Samuel Klatchko
Actually this is a compile time error, on my compiler I get `'NotOnTheHeap::operator new' : cannot access private member declared in class 'NotOnTheHeap'` but it's *also* a link time error since the there's no implementation for the various operators.
Andreas Brinck
+1  A: 

That will mostly achieve what you're trying.

What your solution does not cover is in-place new, which may or may not be on the heap.

Shmoopty
Can it be extended to cover placement new?
dicroce
Nope, placement new is non-replaceable. It simply returns the address it was given.
GMan
The code as it is in the question already covers placement new: `new(some_void_ptr) A` will fail. It doesn't cover `::new(some_void_ptr) A` because when the allocation function is specified explicitly then class overloads aren't considered (applies to all placement forms as well as non-placement, e.g. `::new A`). I'm not sure why GMan mentions this, because you can declare `A::operator new(size_t, void*)`, etc., you can only not replace `::operator new(size_t, void*)`, but the code never replaces the global `::operator new(size_t)` either.
Roger Pate
+10  A: 

Depends on what you mean with "explicitly disallow heap allocation".

If you just want to prevent direct allocation on the heap, i.e.:

NotOnTheHeap *n = new NotOnTheHeap();

it is good enough. But it will not prevent that your object exists on the heap in general.

For example, it won't prevent people from using std::vector <NotOnTheHeap>, which will allocate objects from your class on the heap.

It will also not prevent people from using a NotOnTheHeap as member variable in another class, that is allocated on the heap.

oefe
Explicitly specifying the allocation function, `::new A`, also still works.
Roger Pate
Yeah, I realized this... Thats why I had "Heapable" in the example... To show that it could still exist on the heap indirectly...
dicroce
+1  A: 

You could disable the copy or even default construction, and operator= etc for a more strict scenario (some cases of embedding values or container use).

However, that will move you out of some useful constructs and force you to introduce your own semantics (something more visible in VM impls; lack/induction of similar operator and ambiguous equivalence/equality mechanisms). You will likely see a few compiler warnings too, it won't go all the way, but if its of any consolation it can have a use or two.

rama-jka toti
+1  A: 

Get hold of Scott Meyers' Effective C++ and More Effective C++ -- he covers this sort of stuff. Every C++ programmer should own & read these books.

AAT