0

Could you take a look at these 2 examples and explain me why first attemp of print result gave me wrong number?

First example (printRes pass x by pointer):

int& getInt(int x){
    x++;
    cout << "int " << x << endl;
    return x;
}

void printRes(int *x){
    cout << "res " << *x << endl;
}

int main()
{
    int t = getInt(5);
    printRes(&getInt(5)); // first attemp
    printRes(&t); // second attemp

    return 0;
}

Second example (printRes pass x by reference):

int& getInt(int x){
    x++;
    cout << "int " << x << endl;
    return x;
}

void printRes(int &x){
    cout << "res " << x << endl;
}

int main()
{
    int t = getInt(5);
    printRes(getInt(5)); // first attemp
    printRes(t); // second attemp

    return 0;
}

Results:

int 6
int 6
res 2686640
res 6

When I pass 'x' by value it works ok but my target is to get something like this:

  • function getInt creates object, puts it in vector (so I just call v.emplace_back()) and returns reference to currently added object (v.back())
  • value returned by getInt is passed to printRes which fills object with values from file

I don't want create temporal variables such 't' but pass vector element directly to printRes function but in my more expanded case I have crashes in destructors (or sometimes in some random places).

Harry
  • 144
  • 2
  • 9
  • You could [ask the compiler](http://coliru.stacked-crooked.com/a/d20873013cc5dd8b): *warning: reference to stack memory associated with local variable 'x' returned* – chris Mar 03 '15 at 22:13
  • Thank you, now I see the problem. Interestingly Visual doesn't report this waring. – Harry Mar 26 '15 at 21:14
  • In the VS2015 preview, I get *warning C4172: returning address of local variable or temporary: x*. I don't know about other versions. – chris Mar 26 '15 at 21:56

1 Answers1

0

The reason why the first call to printRes() gives you the wrong result is that getInt() has a serious flaw.

The problem is that getInt() returns a reference to a local variable, and this is no go in C++. The moment getInt() returns, the variable x no longer exists, and any reference to the variable becomes invalid. The result is that the pointer that printRes() receives in the line:

printRes(&getInt(5));

most likely points to nonsense. Same argument goes for the second example.

The reason why the second call to printRes() gives you the right result is luck. When the invalid reference is returned in the line:

int t = getInt(5);

the variable t gets initialized with the value of x, and because it happens right after getInt() returns, the memory where x was stored has not yet been overwritten.

In any case, returning a reference is something you should be cautious about. Check out Is the practice of returning a C++ reference variable, evil?

One way to do what you want, is to define a vector v which is not local in getInt() (so it can exist outside the scope of the function) and return an iterator instead. Like this:

#include <iostream>
#include <vector>

using namespace std;

vector<int> v;

vector<int>::iterator getInt(int x){
    x++;
    cout << "int " << x << endl;
    v.emplace_back(x);
    return --v.end(); // end() points to after last element.
                      // Decrement to get the last element
}

void printRes(vector<int>::iterator i){ 
    cout << "res " << *i << endl;
    *i = 99; //set the element to a new value if you want
}

int main()
{
    printRes(getInt(5));  

    return 0;
}

Please note that the iterator returned from getInt() gets invalidated whenever v.emplace_back() (or similar function) is used, so you shouldn't store it for too long. However, using it immediately, like here, is fine.

Community
  • 1
  • 1
johanmaack
  • 171
  • 2
  • 8