Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing newly allocated data directly to a function

While learning different languages, I've often seen objects allocated on the fly, most often in Java and C#, like this:

functionCall(new className(initializers));

I understand that this is perfectly legal in memory-managed languages, but can this technique be used in C++ without causing a memory leak?

like image 942
Cristián Romo Avatar asked Dec 29 '08 20:12

Cristián Romo


2 Answers

Your code is valid (assuming functionCall() actually guarantees that the pointer gets deleted), but it's fragile and will make alarm bells go off in the heads of most C++ programmers.

There are multiple problems with your code:

  • First and foremost, who owns the pointer? Who is responsible for freeing it? The calling code can't do it, because you don't store the pointer. That means the called function must do it, but that's not clear to someone looking at that function. Similarly, if I call the code from somewhere else, I certainly don't expect the function to call delete on the pointer I passed to it!
  • If we make your example slightly more complex, it can leak memory, even if the called function calls delete. Say it looks like this: functionCall(new className(initializers), new className(initializers)); Imagine that the first one is allocated successfully, but the second one throws an exception (maybe it's out of memory, or maybe the class constructor threw an exception). functionCall never gets called then, and can't free the memory.

The simple (but still messy) solution is to allocate memory first, and store the pointer, and then free it in the same scope as it was declared (so the calling function owns the memory):

className* p = new className(initializers);
functionCall(p);
delete p;

But this is still a mess. What if functionCall throws an exception? Then p won't be deleted. Unless we add a try/catch around the whole thing, but sheesh, that's messy. What if the function gets a bit more complex, and may return after functionCall but before delete? Whoops, memory leak. Impossible to maintain. Bad code.

So one of the nice solutions is to use a smart pointer:

boost::shared_ptr<className> p = boost::shared_ptr<className>(new className(initializers));
functionCall(p);

Now ownership of the memory is dealt with. The shared_ptr owns the memory, and guarantees that it'll get freed. We could use std::auto_ptr instead, of course, but shared_ptr implements the semantics you'd usually expect.

Note that I still allocated the memory on a separate line, because the problem with making multiple allocations on the same line as you make the function call still exists. One of them may still throw, and then you've leaked memory.

Smart pointers are generally the absolute minimum you need to handle memory management. But often, the nice solution is to write your own RAII class.

className should be allocated on the stack, and in its constructor, make what allocations with new are necessary. And in its destructor, it should free that memory. This way, you're guaranteed that no memory leaks will occur, and you can make the function call as simple as this:

functionCall(className(initializers));

The C++ standard library works like this. std::vector is one example. You'd never allocate a vector with new. You allocate it on the stack, and let it deal with its memory allocations internally.

like image 118
jalf Avatar answered Sep 17 '22 14:09

jalf


Yes, as long as you deallocate the memory inside the function. But by no means this is a best practice for C++.

like image 38
Otávio Décio Avatar answered Sep 17 '22 14:09

Otávio Décio