views:

179

answers:

2

Hello,

class Refvect
{
public:
    vector<int> &refv;
    Refvect(int t, vector<int> &refv = vector<int>()) : refv(refv) { };
    void operator()()
    {
        refv.clear();
    }
};
int main () 
{
    Refvect r(0);
    r();
}

With Visual Studio 2010, this gives me an error : "vector iterators incompatible" at the execution, but I don't understand why (but I can insert elements in refv without any problem). The temporary object vector() lives as long as the reference, no?

+4  A: 

As soon as the statement

Refvect r(0);

is executed (control passes beyond the semicolon) the temporary vector<int> &refv = vector<int>() is destroyed. Now the reference stored inside the class object is dangling - not bound to any live object. Trying to access the object through such reference is undefined behavior.

sharptooth
+1. One should store the actual vector instead of a copy to that vector.
Billy ONeal
@Billy - no. one should store a copy of the actual vector instead of a reference to the original most of the time.
Noah Roberts
@Noah Roberts: Thanks for catching my typo. Please replace "copy" with "reference"
Billy ONeal
If it did that, @Billy, it wouldn't be much of a `Refvect` anymore. Storing a reference appears to be the entire purpose of the class. The only change necessary seems to be to remove the possibility of a default argument. In other words, when you want a vector reference, you need to provide your own vector; the reference class can't provide one of its own — at least not through a default parameter.
Rob Kennedy
@Rob Kennedy: I assumed that the class was an example; not real code. If it's purpose is to store the reference then the OP should store the reference, not a class whose sole purpose is to contain that reference.
Billy ONeal
+1  A: 

The temporary object vector() lives as long as the reference, no?

No!

Temporaries destruct at the end of the outermost enclosing expression - i.e. an expression that is embedded in a statement rather than another expression. There is no magic tracking of references to ensure that objects live as long as references to them - that would be garbage collection.

Update:

In response to your comment:

if I use const vector<int> &refv; it works

I'm not sure how that could be. If you add const to the parameter refv then it is no longer compatible with the member and so should not compile. If you change the member to const also then you should find that you cannot call clear on it, because it that is not a const member function.

And if you've found something in C++ that "seems to work", then you're using C++ in completely the wrong way!

There a lots of ways for something to "seem to work" in C++ under highly specific special circumstances, but which will fail more obviously if those circumstances are altered. This is called "undefined behaviour" - the results may include apparent correct behaviour, sometimes.

The most common form is where data ceases to be valid even when there is still a means of accessing it, which is the situation you have here.

The correct way to use C++ is to thoroughly understand the limits of defined behaviour and stay well inside them, as far as you possibly can. In particular you need to understand how long objects live for, so you can ensure that references to objects don't live longer than the objects they refer to.

Daniel Earwicker
Ok, thank you, but now if I use const vector<int> it works?
void