tags:

views:

268

answers:

11

Hi!

I know this won'T work because the variable x gets destroyed when the function returns:

int* myFunction()
{
    int x = 4; return &x;
}

so how do I correctly return a pointer to something I create within the function, and what do I have to take care with? How do I avoid memory leaks?

I've also used malloc:

int* myFunction2()
{
    int* x = (int*)malloc(sizeof int); *x = 4; return x;
}

How do you correctly do this - in C and C++ ?

+6  A: 

Your second approach is correct. You just need to clearly document that the caller "owns" the result pointer, and is responsible for freeing it.

Because of this extra complexity, it is rare to do this for "small" types like int, though I'm assuming you just used an int here for the sake of an example.

Some people will also prefer to take a pointer to an already allocated object as a parameter, rather than allocating the object internally. This makes it clearer that the caller is responsible for deallocating the object (since they allocated it in the first place), but makes the call site a bit more verbose, so it's a trade-off.

Laurence Gonsalves
+5  A: 

For C++, in many cases, just return by value. Even in cases of larger objects, RVO will frequently avoid unnecessary copying.

Fred Larson
+1  A: 

In C++, you should use new:

int *myFunction()
{
    int blah = 4;
    return new int(blah);
}

And to get rid of it, use delete:

int main(void)
{
    int *myInt = myFunction();
    // do stuff
    delete myInt;
}

Note that I'm invoking the copy constructor for int while using new, so that the value "4" is copied onto the heap memory. The only way to get a pointer to something on the stack reliably is to copy it onto the heap by invoking new properly.

EDIT: As noted in another answer, you will also need to document that the pointer needs to be freed by the caller later on. Otherwise you might have a memory leak.

Platinum Azure
+2  A: 

Hi,

C++ approach to avoid memory leaks. (at least when You ignore function output)

std::auto_ptr<int> myFunction() {
    std::auto_ptr<int> result(new int(4));
    return result;
}

Then call it:

std::auto_ptr<int> myFunctionResult = myFunction();

EDIT: As pointed out by Joel. std::auto_ptr has it's own drawbacks and generally should be avoided. Instead std::auto_ptr You could use boost::shared_ptr (std::tr1::shared_ptr).

boost::shared_ptr<int> myFunction() {
    boost::shared_ptr<int> result(new int(5));
    return result;
}

or when use C++0x conforming compiler You can use std::unique_ptr.

std::tr1::unique_ptr<int> myFunction() {
    std::tr1::unique_ptr<int> result(new int(5));
    return result;
}

The main difference is that:

  • shared_ptr allows multiple instances of shared_ptr pointing to the same RAW pointer. It uses reference counting mechanism to ensure that memory will not be freed as long as at least one instance of shared_ptr exist.

  • unique_ptr allows only one instance of it holding pointer but have true move semantic unlike auto_ptr.

lollinus
auto_ptr is generally frowned on because it has bizarre semantics. When you pass that result to a function, you no longer own it and can't actually access it anymore.
Joel
You are right and I agree completely. That is why I've wrote (at least when You ignore function output).Better solution is for example boost::shared_ptr but I suggested currently standarized solution. And Yes I know about std::tr1::shared_ptr
lollinus
@Joel: If you pass it to another function, that function probably won't take an auto_ptr. So you'd use `f(myFunctionResult.get())` and still retain ownership. If the function does take an auto_ptr, it's clear that ownership is transferred.
Fred Larson
I don't agree that `shared_ptr` is a better solution in this case. The memory is not shared at all, but rather passed along. `auto_ptr` is very explicit in the 'transfer of ownership' semantics for this particular case. In the upcoming standard you would probably use `unique_ptr` (also available in boost).
David Rodríguez - dribeas
unique_ptr is not directly available in boost::smart ptr library but is rather hidden in inter process library as long as I remember correctly.
lollinus
+8  A: 

For C++, you can use a smart pointer to enforce the ownership transfer. auto_ptr or boost::shared_ptr are good options.

Fred Larson
+3  A: 

One possibility is passing the function a pointer:

void computeFoo(int *dest) {
    *dest = 4;
}

This is nice because you can use such a function with an automatic variable:

int foo;
computeFoo(&foo);

With this approach you also keep the memory management in the same part of the code, ie. you can’t miss a malloc just because it happens somewhere inside a function:

// Compare this:
int *foo = malloc(…);
computeFoo(foo);
free(foo);

// With the following:
int *foo = computeFoo();
free(foo);

In the second case it’s easier to forget the free as you don’t see the malloc. This is often at least partially solved by convention, eg: “If a function name starts with XY, it means that you own the data it returns.”

An interesting corner case of returning pointer to “function” variable is declaring the variable static:

int* computeFoo() {
    static int foo = 4;
    return &foo;
}

Of course this is evil for normal programming, but it might come handy some day.

zoul
A: 

There is another approach - declare x static. In this case it will be located in data segment, not on stack, therefore it is available (and persistent) during the program runtime.

int *myFunction(void)
{
    static int x = 4;
    return &x;
}

Please note that assignment x=4 will be performed only on first call of myFunction:

int *foo = myFunction();   // foo is 4
*foo = 10;                 // foo is 10
*foo = myFunction();       // foo is 10

NB! Using function-scope static variables isn't tread-safe technique.

qrdl
Why the downvote? My answer is completely correct.
qrdl
A: 

Boost or TR1 shared pointers are generally the way to go. It avoids the copy overhead, and gives you semi-automatic deletion. So your function should look like:

boost::shared_ptr<int> myFunction2()
{
    boost::shared_ptr<int> x = new int; 

    *x = 4; 
    return x;
}

The other option is just to allow a copy. That's not too bad if the object is small (like this one) or you can arrange to create the object in the return statement. The compiler will usually optimize a copy away if the object is created in the return statement.

Joel
A: 

I would try something like this:

int myFunction2b( int * px )
{
  if( px )
  {
    *px = 4;
    return 1;
  }

  // Choice 1: Assert or Report Error
  // Choice 2: Allocate memory for x. Caller has to be written accordingly.

  // My choice is 1
  assert( 0 && "Argument is NULL pointer" );
  return 0;

}
ArunSaha
A: 

You're asking how to correctly return a pointer. That's the wrong question, because what you should be doing is using smart pointers rather than raw pointers. scoped_ptr and shared_ptr (available in boost and tr1) are good pointers to look at (e.g. here and here)

If you need the raw pointer for something (e.g. passing to a C function), the get() method will supply it.

If you must create raw pointers, e.g. for homework, then you can use malloc() (as you did) or new within a function, and hope you remember to de-allocate the memory (through free() and delete respectively) Or, in a slightly-less-likely-to-leak idiom, you can create the pointer with new, pass it to a function, and de-allocate with delete when you're done with it. Again, though, use smart pointers.

Liz Albin
A: 

Your second code snippet is correct.

To help avoid memory leaks, I let the coding conventions help me.

xxxCreate() will allocate memory for xxx and initialize it. xxxDelete() will destroy/corrupt xxx and free it.

xxxInit() will initialize xxx (never allocate) xxxDestroy() will destroy/corrupt xxx (never free)

Additionally, I try to add the code to delete/destroy/free as soon as I add the code to create/init/malloc. It's not perfect, but I find that it helps me differentiate between items that need to be freed and those that don't, as well as reducing the likelihood that I will forget to free something at a later time.

Sparky