Thread: Plz explain difference between functions returning ref

  1. #1
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391

    Plz explain difference between functions returning ref

    Check out this example:
    Code:
    #include <iostream>
    
    class foo{
    };
    
    foo& fn1(){
    	
    	foo f;
    	return f;
    }
    
    foo& fn2(){
    	
    	foo* f_ptr = new foo();
    	return *f_ptr;
    }
    
    int main(){
    	
    	foo& f_ref = fn1(); // Compiler warning here
    	
    	foo& f_ref2 = fn2();
    	
    	return 0;
    }
    When I compile this, I only get the warning for "reference to local variable 'f' returned" when fn1() is called.

    What's the difference between fn1() and fn2(), besides the obvious use of a foo pointer in fn2()?

    Why do I only get the warning for fn1()?

    Isn't fn2() returning a reference to a local variable as well?
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Isn't fn2() returning a reference to a local variable as well?
    No, it returns a reference to an object whose lifetime extends beyond the scope of fn2(). I believe you should actually do a:
    Code:
    delete &f_ref2;
    though personally I would return a pointer instead of a reference from fn2().
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    When you use new to allocate an object, it remains alive until you delete it.

    When you declare a variable locally, it is destroyed when the current scope exits.

    So in your first example, you are returning a reference to an object that is destroyed when the function ends. That's bad. In the second example, you are returning a reference to an object that remains alive until you delete it. Normally you would return a pointer instead of a reference (and even better a smart pointer) to dynamically allocated objects. You should save returning by reference for when you have an object that is not declared locally in the function, like a class member for example.

    Also note that you are leaking the memory allocated in fn2() because you never deleted. The same rule that makes the reference to f in fn1() bad is the rule that cleans it up automatically. That rule does not apply to the dynamically allocated object.

  4. #4
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Quote Originally Posted by laserlight View Post
    No, it returns a reference to an object whose lifetime extends beyond the scope of fn2(). I believe you should actually do a:
    Code:
    delete &f_ref2;
    though personally I would return a pointer instead of a reference from fn2().
    Okay, so let's say I want to have a function that returns a reference to an STL container, like this:
    Code:
    std::list<int>& getAList(){
    
      std::list<int>* aList;
    
      // Populate the list
    
      return *aList;
    }
    That's the "preferred" way to do that? If that function is called in main(), it's "scope" is within main()?
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  5. #5
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Quote Originally Posted by Daved View Post
    When you use new to allocate an object, it remains alive until you delete it.

    When you declare a variable locally, it is destroyed when the current scope exits.

    So in your first example, you are returning a reference to an object that is destroyed when the function ends. That's bad. In the second example, you are returning a reference to an object that remains alive until you delete it. Normally you would return a pointer instead of a reference (and even better a smart pointer) to dynamically allocated objects. You should save returning by reference for when you have an object that is not declared locally in the function, like a class member for example.

    Also note that you are leaking the memory allocated in fn2() because you never deleted. The same rule that makes the reference to f in fn1() bad is the rule that cleans it up automatically. That rule does not apply to the dynamically allocated object.
    Okay, forget my last reply.

    So it's better to use functions like:
    Code:
    std::list<int>* getAListPointer(){
    }
    
    // or:
    
    void getAListReference( std::list<int>& aList ){
    
        // Populate a list declared in main.
    }
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Okay, so let's say I want to have a function that returns a reference to an STL container, like this:
    ...
    That's the "preferred" way to do that?
    Instead of saying "I want to have a function that returns a reference to an STL container", you should say "I want to return a container, should I return a copy, a reference, or a pointer?"

    In other words, decide what to return based on the situation, not concoct a situation to satisfy the method you want to use to return.

    If that function is called in main(), it's "scope" is within main()?
    The scope of that function is its body, not the body of its caller.

    EDIT:
    So it's better to use functions like:
    Again, this depends on the situation. Generally I would prefer an out parameter, i.e., the second version. If you return a pointer it implies manual memory management unless you return a smart pointer.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Code:
    void fillAList( std::list<int>& aList )
    That's what I'd use.

    In some cases this is also ok:
    Code:
    std::list<int> fillAList()
    The first is almost always good. The second is ok if the list is not big because it (might) make a copy which is expensive for big lists.

    Returning by reference (or pointer) only make sense if the list already exists somewhere and you're just returning a reference to the existing list (again, the example is a list that is a member of a class).

  8. #8
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Again, this depends on the situation. Generally I would prefer an out parameter, i.e., the second version. If you return a pointer it implies manual memory management unless you return a smart pointer.
    Yeah, that makes the most sense.

    Basically I had a function that displays the search path of a tree. I figured it would be nice if not only did it cout the path to the console window, but what if you could return a list of those results as well (killing 2 birds with one stone if you will)

    So the function could be called with or without using the return parameter like:
    Code:
    std::list<int>& getSearchPath();
    
    int main(){
    
      list<int>& listRef1 = getSearchPath();
    
      // Or, if you only want to print the results:
    
      getSearchPath(); // Not using return parameter
    
      return 0;
    }
    That's the situation of mine that arose. So in this situation, is it better to have a void getSearchPath( list<int>& ) and write another function to display those results, or simply break it up into 2 different functions, each with their own purpose?
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Have each function do one thing. And consider overriding operator<< for output.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 05-07-2002, 04:18 AM
  2. returning functions w/ sockets
    By JagWire in forum Windows Programming
    Replies: 4
    Last Post: 03-11-2002, 05:00 PM
  3. string.h functions help plz :)
    By ChrisE in forum C++ Programming
    Replies: 1
    Last Post: 03-05-2002, 03:12 PM
  4. Passing & Returning Strings from Functions
    By nisaacs in forum C Programming
    Replies: 1
    Last Post: 01-30-2002, 05:34 AM
  5. Class accessor functions returning strings?
    By Shadow12345 in forum C++ Programming
    Replies: 6
    Last Post: 12-31-2001, 12:48 PM