Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allocate memory on stack without calling constructor

Tags:

c++

I'd like to keep MyClass in the stack memory (simpler, faster) in the following code, but avoid calling the default constructor:

#include <iostream>

class MyClass {
public:
  MyClass() {
    std::cout << "MyClass()" << std::endl;
  }

  MyClass(int a) {
    std::cout << "MyClass(" << a << ")" << std::endl;
  }

  MyClass(const std::string& a) {
    std::cout << "MyClass(\"" << a << "\")" << std::endl;
  }

  void doStuff() {
    std::cout << "doStuff()" << std::endl;
  }
};

int main(int argc, char* argv[]) {
  bool something;
  if (argc > 1)
    something = 1;
  else
    something = 0;

  MyClass c;
  if (something)
    c = MyClass(1);
  else
    c = MyClass("string");
  c.doStuff();

  return 0;
}

As far as I know, the only way to avoid calling the default constructor would be to use a pointer, but then I would have to allocate in the heap and deal with memory management. Is there any other way?

like image 606
egoard Avatar asked Aug 20 '13 23:08

egoard


People also ask

How do you allocate space on a stack?

We can allocate variable length space dynamically on stack memory by using function _alloca. This function allocates memory from the program stack. It simply takes number of bytes to be allocated and return void* to the allocated space just as malloc call.

Does constructor allocate memory?

A constructor does not allocate memory for the class object its this pointer refers to, but may allocate storage for more objects than its class object refers to. If memory allocation is required for objects, constructors can explicitly call the new operator.

Do you need to manually allocate memory in C++?

In C language, we use the malloc() or calloc() functions to allocate the memory dynamically at run time, and C++ also supports these functions. But, in C++, allocation and deallocation are done manually.

What is the point of malloc?

malloc is used to allocate memory. You can use a pointer by either allocating it with malloc or making it point to an already allocated portion of memory.


2 Answers

If you don't mind using a total hack, you can try a placement new.

char mem[sizeof(MyClass)] alignas(MyClass);
auto custom_deleter = [](MyClass *p){ p->~MyClass(); };
std::shared_ptr<MyClass> c(new (mem) MyClass, custom_deleter);

You use the alignas to make sure the automatic memory allocated is properly aligned for your object. The custom_deleter function calls the destructor without freeing the memory, which is needed when using automatic memory with a smart pointer. A demo of the code can be found here.

But, for your problem a more elegant solution exists. You can use a copy constructor instead:

  MyClass c = something ? MyClass(1) : MyClass("string");
  c.doStuff();
like image 74
jxh Avatar answered Nov 11 '22 17:11

jxh


You're right. It isn't possible for you do avoid calling the default constructor, unless you want to duplicate some code like shown below.

if (something) {
    MyClass c(1);
    c.doStuff();
}
else {
    MyClass c("string");
    c.doStuff();
}

I would recommend that you create the object of the heap, but delegate the memory handling to another class. With C++03, there is the std::auto_ptr class which can be used. With C++11, auto_ptr has be deprecated, and instead you can use shared_ptr or unique_ptr.

Here is some example code using shared_ptr -

std::shared_ptr<MyClass> c;
if (something)
    c.reset(new MyClass(1));
else 
    c.reset(new MyClass("string"));

c->doStuff();

The object will automatically be deleted when it goes out of scope.

In general, it is recommended to use smart pointers instead of doing the memory management yourself. This is especially useful when you're dealing with code that can throw exceptions.

like image 44
Vishesh Handa Avatar answered Nov 11 '22 17:11

Vishesh Handa