Returning a Reference to an Object on the Heap

You might be tempted to solve the problem in Listing 12.4 by having TheFunction() create Frisky on the heap. That way, when you return from TheFunction(), Frisky will still exist.

The problem with this approach is: What do you do with the memory allocated for Frisky when you are done with it? Listing 12.5 illustrates this problem.

Listing 12.5. Memory Leaks
 0:  // Listing 12.5
 1:  // Resolving memory leaks
 2:  #include <iostream>
 3:
 4:  class SimpleCat
 5:  {
 6:  public:
 7:      SimpleCat (int age, int weight);
 8:      ~SimpleCat() {}
 9:      int GetAge() { return itsAge; }
10:      int GetWeight() { return itsWeight; }
11:
12:  private:
13:      int itsAge;
14:      int itsWeight;
15:  };
16:
17:  SimpleCat::SimpleCat(int age, int weight):
18:  itsAge(age), itsWeight(weight) {}
19:
20:  SimpleCat & TheFunction();
21:
22:  int main()
23:  {
24:      SimpleCat & rCat = TheFunction();
25:      int age = rCat.GetAge();
26:      std::cout << "rCat is " << age << " years old!
";
27:      std::cout << "&rCat: " << &rCat << std::endl;
28:      // How do you get rid of that memory?
29:      SimpleCat * pCat = &rCat;
30:      delete pCat;
31:      // Uh oh, rCat now refers to ??
32:      return 0;
33:  }
34:
35:  SimpleCat &TheFunction()
36:  {
37:      SimpleCat * pFrisky = new SimpleCat(5,9);
38:      std::cout << "pFrisky: " << pFrisky << std::endl;
39:      return *pFrisky;
40:  }


pFrisky: 0x00431CA0
rCat is 5 years old!
&rCat: 0x00431CA0
					

This compiles, links, and appears to work. But it is a time bomb waiting to go off.


The function TheFunction() has been changed so that it no longer returns a reference to a local variable. Memory is allocated on the heap and assigned to a pointer on line 37. The address that pointer holds is printed, and then the pointer is dereferenced and the SimpleCat object is returned by reference.


On line 24, the return of TheFunction() is assigned to a reference to a SimpleCat, and that object is used to obtain the cat's age, which is printed on line 26.

To prove that the reference declared in main() is referring to the object put on the heap in TheFunction(), the address of operator is applied to rCat. Sure enough, it displays the address of the object it refers to, and this matches the address of the object on the heap.

So far, so good. But how will that memory be freed? You can't call delete on the reference. One clever solution is to create another pointer and initialize it with the address obtained from rCat. This does delete the memory and plugs the memory leak. One small problem, though: What is rCat referring to after line 31? As stated earlier, a reference must always be an alias for an actual object; if it references a null object (as this does now), the program is invalid.

It cannot be overemphasized that a program with a reference to a null object might compile, but it is invalid and its performance is unpredictable.


There are actually two solutions to this problem. The first is to return a pointer to the memory created on line 37. Then the calling function can delete the pointer when it is done. To do this, change the return value of TheFunction to pointer (rather than reference) and return the pointer, rather than the dereferenced pointer:

SimpleCat * TheFunction()
{
    SimpleCat * pFrisky = new SimpleCat(5,9);
    std::cout << "pFrisky: " << pFrisky << std::endl;
    return pFrisky;  // return the pointer
}

The alternative and more desirable solution is to declare the object in the calling function and then to pass it to TheFunction() by reference. The advantage of this alternative is that the function that allocates the memory (the calling function) is also the function that is responsible for de-allocating it, which, as you'll see in the next section, is preferable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.170.92