Like Tree7Likes
  • 1 Post By laserlight
  • 3 Post By Imanuel
  • 1 Post By laserlight
  • 2 Post By CornedBee

List Initializing Return Value

This is a discussion on List Initializing Return Value within the C++ Programming forums, part of the General Programming Boards category; Why does the following happen? Code: vector<int> toReturn(void); vector<int> toReturn(void){ return {2, 4, 6, 8, 10}; } int main(int argc, ...

  1. #1
    Registered User
    Join Date
    May 2010
    Posts
    178

    List Initializing Return Value

    Why does the following happen?

    Code:
    vector<int> toReturn(void);
    vector<int> toReturn(void){
    	return {2, 4, 6, 8, 10};
    }
    
    int main(int argc, char *argv[]){
    
    	vector<int>::iterator iter = toReturn().begin();
    	for(; iter != toReturn().end(); ++iter){
    		cout << *iter << " ";
    	}
    	cout << endl;
    }
    Output:

    Code:
    6098688 6105968 6 8 10
    The first two values of the output change with each run of the program. I am using Eclipse and the MinGW gcc compiler with the c++11 flag.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,720
    Everytime you call toReturn, it returns a different vector.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    178
    Check the output though .. wrong. Should be 2 4 6 8 10 but instead the first two numbers appear to be integer representations of some large number. That is wrong and I would like to know why.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,720
    Quote Originally Posted by Imanuel
    Check the output though .. wrong. Should be 2 4 6 8 10 but instead the first two numbers appear to be integer representations of some large number. That is wrong and I would like to know why.
    I already told you why: everytime you call toReturn, it returns a different vector. Therefore, your call to begin() returns an iterator that is the beginning of a range, but your call to end() returns an iterator that is one past the end of a different range.

    You can fix this with say:
    Code:
    vector<int> numbers = toReturn();
    vector<int>::iterator iter = numbers.begin();
    for(; iter != numbers.end(); ++iter){
        cout << *iter << " ";
    }
    Now the begin and end iterators denote the same range, i.e., the entire range of the numbers vector.
    Elysia likes this.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    178
    Ah, ok but why is it the output is correct for the last three numbers but not the first two? I am expecting 2 4 6 8 10 and not the output I showed.

    Is this because I am getting a different vector each time? Then why is the output corrupted? This I would like to know.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,720
    Consider this line:
    Code:
    vector<int>::iterator iter = toReturn().begin();
    you create a vector by calling toReturn(), then get an iterator to the first element of the vector, and then the vector is destroyed after the statement.

    The point is, the vector is destroyed. Therefore, the memory occupied by its elements can now be reused for other purposes. This explains the corrupted output, especially since this "create vector, get an iterator, then destroy it before using the iterator" process is repeated in the loop itself, except that for that one you're getting the one past the end iterator.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    178
    Sorry you had to spell that out for me but now I completely understand and the pieces have fallen into place inside my noodle. Thank you.
    laserlight, iMalc and Elysia like this.

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,304
    Of course it would also work if toReturn was declared like this:
    Code:
    vector<int>& toReturn() {
        static vector<int> x = {2, 4, 6, 8, 10};
        return x;
    }
    Assuming I got the syntax correct, since I haven't used that form of vector initialisation myself yet.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,720
    Of course, if you do that, then you get the various drawbacks associated with returning static local variables, so you might as well just get rid of the toReturn function.
    King Mir likes this.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Since you're using list-initialization, why not all the other nice features of C++11?
    Code:
    vector<int> toReturn(){ // Using void to denote an empty parameter list is from C and has always been unusual for C++.
        return {2, 4, 6, 8, 10};
    }
     
    int main(){ // If you don't use the command line arguments, why not use the parameter-less version of main?
      auto v = toReturn(); // Don't really need to spell out the type here. You could though, if it's not obvious that toReturn gives you a vector<int>.
        // (In this little example, it isn't, since toReturn isn't meaningful. But then, it's just a small example.)
      for(auto iter = v.begin(); iter != v.end(); ++iter){ // This is where auto really shines. Do you really want to type vector<int>::iterator?
        cout << *iter << " ";
      }
    
      // Or just write this:
      for(auto i : v) { // Range-based for loop FTW!
        cout << i << " ";
      }
    
      // Or since the rbfl keeps temporaries alive:
      for(auto i : toReturn()) {
        cout << i << " ";
      }
    
      cout << endl;
    }
    Salem and Elysia like this.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Initializing a Linked List
    By Marth_01 in forum C Programming
    Replies: 1
    Last Post: 03-21-2009, 11:26 PM
  2. Replies: 1
    Last Post: 07-04-2007, 12:20 AM
  3. Replies: 12
    Last Post: 04-07-2007, 11:11 AM
  4. Replies: 6
    Last Post: 04-09-2006, 04:32 PM
  5. Replies: 4
    Last Post: 07-15-2005, 04:10 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21