How do I allocate a polymorphic object on the stack? I\'m trying to do something similar to (trying to avoid heap allocation with new)?:
A* a = NULL;
switch
I wrote a generic template to do it. Full code available here (it became too elaborate for the scope of this question). StackVariant object contains a buffer of the size of the biggest type out of the provided types, and biggest alignment as well. The Object is constructed on the stack using a 'placement new' and operator->() is used for polymorphic access to suggest the indirection. Also, it is important to make sure that if a virtual detor is defined, it should be called upon destruction of the object on the stack, so the template detor is doing just that using a SFINAE definition.
(see usage example and output below):
// compile: g++ file.cpp -std=c++11
#include
#include
// union_size()/union_align() implementation in gist link above
template
class StackVariant {
alignas(union_align()) char storage[union_size()];
public:
inline Tbaseclass* operator->() { return ((Tbaseclass*)storage); }
template
StackVariant& init(TCtor_params&&...fargs)
{
new (storage) C(std::forward(fargs)...); // "placement new"
return *this;
};
template
typename std::enable_if::value, void>::type
call_dtor(){
((X*)storage)->~X();
}
template
typename std::enable_if::value, void>::type
call_dtor() {};
~StackVariant() {
call_dtor();
}
};
Usage example:
#include
#include
#include "StackVariant.h"
class Animal{
public:
virtual void makeSound() = 0;
virtual std::string name() = 0;
virtual ~Animal() = default;
};
class Dog : public Animal{
public:
void makeSound() final { std::cout << "woff" << std::endl; };
std::string name() final { return "dog"; };
Dog(){};
~Dog() {std::cout << "woff bye!" << std::endl;}
};
class Cat : public Animal{
std::string catname;
public:
Cat() : catname("gonzo") {};
Cat(const std::string& _name) : catname(_name) {};
void makeSound() final { std::cout << "meow" << std::endl; };
std::string name() final { return catname; };
};
using StackAnimal = StackVariant;
int main() {
StackAnimal a1;
StackAnimal a2;
a1.init("gonzo2");
a2.init();
a1->makeSound();
a2->makeSound();
return 0;
}
// Output:
// meow
// woff
// woff bye!
Few things to note: