views:

217

answers:

8

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?

+6  A: 

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

Otávio Décio
What would be a better practice then?
Cristián Romo
Allocate, call function, deallocate. Extra variable needed to point to the allocated object.
Otávio Décio
As usual, the better practice is RAII. If you have calls to new visible in your user code, the odds are good that you're Doing It Wrong. At least wrap the allocation in a smart pointer. I just added an answer demonstrating this.
jalf
If U can change the function's code then put the new in there, and pass the initilizers. Keep the variables as local as u can. If U don't have access to the code, then this WILL cause a mem leak. Create a pointer to the new object, one line up and pass that in..
baash05
BTW.. That's best in c# too, function's in fuction calls is always a bad idea for debugging. One idea per line. :)
baash05
+5  A: 

It depends.

This passes "ownership" of the memory to functionCAll(). It will either need to free the object or save the pointer so that it can be freed later. Passing the ownership of raw pointers like this is one of the easiest ways to build memory issues into your code -- either leaks or double deletes.

Darron
And passing ownership like this is usually a messy deal, because it's not obvious, from looking at a raw pointer who owns it.
jalf
Absolutely. I'm editing the answer to expand upon that.
Darron
A: 

This will work for objects created on the stack, but not a regular pointer in C++.

An auto pointer maybe able to handle it, but I haven't messed with them enough to know.

shrub34
A regular auto_ptr won't (the function call itself makes a copy of the auto_ptr, which makes for a transfer of ownership), but a const auto_ptr should (if I understood Josuttis' book correctly) do what you'd expect.
Harper Shelby
A: 

In general, no, unless you want to leak memory. In fact, in most cases, this won't work, since the result of

new T();

in C++ is a T*, not a T (in C#, new T() returns a T).

Harper Shelby
A: 

Have a look at Smart Pointers or A garbage collector for C and C++.

Ronald Blaschke
+1  A: 

It is safe if the function that you are calling has acceptance-of-ownership semantics. I don't recall a time where I needed this, so I would consider it unusual.

If the function works this way, it should take its argument as a smart pointer object so that the intent is clea; i.e.

void functionCall(std::auto_ptr<className> ptr);

rather than

void functionCall(className* ptr);

This makes the transfer of ownership explicit, and the calling function will dispose of the memory pointed to by ptr when execution of the function falls out of scope.

JohnMcG
+12  A: 

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.

jalf
Avoid constructing a null ptr, and the assigning it, you are not garaunteed that T p = T(x) will be compiled optimised as T p(x);ie.boost::shared_ptr<className> p(new className(initializers));In this specific case you might also consider std::auto_ptr to be memory safe, no sharing necessary.
Greg Domjan
+3  A: 

In C++ we would not create the memory dynamically like that.
Instead you would create a temporary stack object.

You only need to create a heap object via new if you want the lifetime of the object to be greater than the call to the function. In this case you can use new in conjunction with a smart pointer (see other answers for an example).

// No need for new or memory management just do this
functionCall(className(initializers));

// This assumes you can change the functionCall to somthing like this.
functionCall(className const& param)
{
    << Do Stuff >>
}

If you want to pass a non const reference then do it like this:

calssName tmp(initializers);
functionCall(tmp);

functionCall(className& param)
{
    << Do Stuff >>
}
Martin York