views:

237

answers:

5

Is there a way to define a macro (or something similar) that would allow objects to be allocated on the stack or on the heap, cleanly?

eg. Current code:

A a;
a.someFunc();

The simplest suggestion might be the following, but as you can see below, it's not very clean to maintain 2 sets of code.

#ifdef USE_STACK
  A a;
  a.someFunc();
#elseif USE_HEAP
  A* a = new A();
  a->someFunc();
#endif

I am looking for a design pattern / proxy class that can be use to compile the code either way, depending on the needs of our customer.

Edit: The code is used to build a library for embedded device / (embedded) Linux / Windows Mobile. Most customers want stack based allocation only. A few others have asked to trade stack for heap.

Thanks, Charles

+1  A: 

Usually the stack is limited in size, so any large objects need to be heap allocated anyway.

All instances that implement a RAII guard idiom (e.g. to aquire and release a mutex) need to be placed on the stack, so that they get cleaned up if you leave the context (e.g. by return or exception)

An idiom that let you switch is generally not very useful, as a careful decision needs to be made as weather to place objects on the stack or on the heap. Usually one or the other will suite the problem better and then it would not make sense to switch.

lothar
they don't, you need to use a smart pointer to achieve the same technique. the smart pointer is stack-based, but the memory it contains makes use of the heap.
gbjbaanb
+2  A: 

Something like this could help:

template <typename T>
class HeapWrapper
{
#ifdef USE_STACK
  T obj_;
#else
  T *obj_;
#endif
public:
#ifdef USE_STACK
  HeapWrapper() : obj_() {}
#else
  HeapWrapper() : obj_(new T()) {}
#endif

#ifdef USE_STACK
  const T& obj() const
  { return obj_; }

  T& obj() const
  { return obj_; }
#else
  const T& obj() const
  { return *obj_; }

  T& obj() const
  { return *obj_; }
#endif
};

However, note that this either limits you to objects with default constructor only. The wrapped class could provide an Init(...) function which could be forwarded by a variadic template function by the wrapper class (or simply add a template <typename T1, template T2, [etc]> Init(const T1 &x1, cons tT2 &x2) for each arity you need):

template <typename T1>
void Init(const T1& x1)
{
#ifdef USE_STACK
  obj_.Init(x1);
#else
  obj_->Init(x1);
#endif
}

template <typename T1, typename T2>
void Init(const T1& x1, const T2& x2)
{
#ifdef USE_STACK
  obj_.Init(x1, x2);
#else
  obj_->Init(x1, x2);
#endif
}

Bonus points if your compiler has variadic templates already:

template<typename... T>
void foo(const T&... values) {
#ifdef USE_STACK
  obj_.Init(values...);
#else
  obj_->Init(values...);
#endif
}
Manuel
why not do the variadic template thing with the actual constructor?
Evan Teran
Hey Manuel, great idea, could use expand your example to show how to use HeapWrapper with object A above and call a.someFunc()?
Charles
@Evan: I was not sure that this would work. Good call!
Manuel
@Manuel: I posted an answer which expands yours a little bit (has nicer syntax in a few minor ways) and covers assignment properly.
Evan Teran
Also you forgot to delete obj_ when in heap mode :-P.
Evan Teran
+2  A: 

If you're asking this question, I think you should start looking into a custom allocator. For starters, if you allocate a big block of memory, you could use that like a stack or a heap by changing the allocator internals. You would allocate all objects using a smart pointer (to prevent memory leaks) and all memory would be handed out to you from your custom heap.

This allows you to tune the allocation implementation according to your customer's needs, whilst also giving you the performance of a stack-based allocator if tuned that way.

Your code would always use "heap" style object creation so you'd only need 1 way of coding and you wouldn't need the conditional macros. Check out block allocators (that create several heaps of fixed-size blocks, you give the first free block of the next size up to the caller(eg blocks are 16 bytes, 32 bytes, 64 bytes etc in size), its very fast to allocate and free, though it is inefficient with memory usage).

gbjbaanb
A: 

Not a final answer, but i hope it can help :

#ifdef USE_STACK
  A a;
#elseif USE_HEAP
  auto_ptr<A> CAUTION_USE_OF_AUTOPTR_a( new A() );
  A& a = CAUTION_USE_OF_AUTOPTR_a.get();
#endif
a.someFunc();
Benoît
+4  A: 

EDIT: improved to allow calling of wrapped member functions through operator->

Expanding on Manuel's answer to make it more complete, try this:

#include <iostream>

#define USE_STACK

template <class T>
class HeapWrapper {
#ifdef USE_STACK
    T obj_;
#else
    T *obj_;
#endif
public:
#ifdef USE_STACK
    HeapWrapper() : obj_() {}

    template <class A1>
    HeapWrapper(const A1 &a1) : obj_(a1) {}

    template <class A1, class A2>
    HeapWrapper(const A1 &a1, const A2 &a2) : obj_(a1, a2) {}

    // etc

#else
    HeapWrapper() : obj_(new T()) {}
    ~HeapWrapper() { delete obj_; }

    template <class A1>
    HeapWrapper(const A1 &a1) : obj_(new T(a1)) {}

    template <class A1, class A2>
    HeapWrapper(const A1 &a1, const A2 &a2) : obj_(new T(a1, a2)) {}

    // etc
#endif

#ifdef USE_STACK
    operator const T &() const    { return obj_; }
    operator T &()                { return obj_; }
    T *operator->()               { return &obj_; }
    T& operator*()                { return obj_; }
#else
    operator const T &() const    { return *obj_; }
    operator T &()                { return *obj_; }
    T *operator->()               { return obj_; }
    T& operator*()                { return *obj_; }
#endif

    // cast operators makes this work nicely
    HeapWrapper &operator=(const T &rhs) { *obj_ = rhs; return *this;}
};


class A {
public:
    void member(int x) {
        std::cout << x << std::endl;
    }
};


int main() {
    HeapWrapper<int> x1(5);
    HeapWrapper<int> x2;
    HeapWrapper<int> x3 = x1;
    HeapWrapper<int> x4 = 3;

    std::cout << x1 << " " << x2 << " " << x3 << " " << x4 << std::endl;

    // example using a custom class's members..
    HeapWrapper<A> a1;
    a1->member(5);
}
Evan Teran
This looks really good, Evan. Is there a way to encapsulate this inside the class A? It would be easier to change one class than to update all the client code as shown above.
Charles
Well to do that, you use a factory pattern. Basically you add a static function to A which returns HeapWrapper<A> or something like that. Unfortunately, it would still require changing all code which create A's object. Not really a huge difference in the number of changes you'd have to make.
Evan Teran
Also, why did someone downvote this? It is an improvement on the currently highest voted answer...
Evan Teran
Thanks Evan, I will study this for a bit.
Charles
The only real annoyance I can think of is that you can't overload operator. (but operator-> is fair game). So if you want to call members, you have to make it look like a pointer. I'll add an example of that working too... Just a sec.
Evan Teran
I was just thinking about your question. Why not just rename "A" to something like "A_impl" and then "typedef HeapWrapper<A_impl> A;" then the only change to the code is how you call members (switch all A.member() to A->member())
Evan Teran