tags:

views:

98

answers:

4

Possible Duplicate:
c++ warning: address of local variable

Hi, When i write this code:

//Returns the transpose matrix of this one
SparseMatrix& SparseMatrix::transpose()const{
    vector<Element> result;
    size_t i;
    for(i=0;i<_matrix.size();++i){
        result.push_back(Element(_matrix.at(i)._col, _matrix.at(i)._row, _matrix.at(i)._val));
    }

    return SparseMatrix(numCol,numRow,result);
}

I get the warning "returning address or local variable or temporary". The last line calls the SparseMatrix constructor. I don't understand what's wrong with this code, and how can i fix it so i can return a SparseMatrix object as i want.

+7  A: 

You're returning a reference, not an actual object - note the & here:

SparseMatrix& SparseMatrix::transpose()const{

If you want to return the actual object, remove that &.

The last line does indeed call the constructor, but it doesn't return the resulting object. That object immediately gets destroyed, and an invalid reference to it gets returned.

RichieHindle
kartheek
thanks! I haven't noticed i've declared it as a ref return value.
limlim
A: 

In C++, local variables are 'automatically' destructed when going out of scope. Your return statement will create a nameless, temporary variable of type SparseMatrix that will immediately go out of scope. Hence, returning a reference to it doesn't make sense.

It may be easier to return by value: then a copy of the temporary will be returned. The compiler can optimize that away (copy elision).

If you really want to pass an object out of a function, you should create it on the heap, using new:

SparseMatrix* SparseMartix::transopse()const{


     //...
     return new SparseMatrix(...);

}

But then, you need to take care of the lifetime of the returned object yourself.

xtofl
A: 

The construct 'T()' creates a temporary of type 'T' which is basically not an Lvalue (but an Rvalue).

$12.1/11 - "A functional notation type conversion (5.2.3) can be used to create new objects of its type. [ Note: The syntax looks like an explicit call of the constructor.

12 An object created in this way is unnamed. [ Note: 12.2 describes the lifetime of >temporary objects. —end note ] [ Note: explicit constructor calls do not yield lvalues, see 3.10. —end note ] The lifetime of this temporary is the end of the full expression i.e. the ending semicolon after the expression.

$12.2/3 - "Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression."

$12.2/5- 'The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement."

Therefore your function tries to return a reference to a memory location whose storage duration is already over and the object has been destroyed.

Therefore a warning. Note that this situation is not required to be explicitly diagnosed by the Standard and hence a warning.

Chubsdad
A: 

If you really want to return a reference (for whatever reason) you'll have to make it a const reference; that'll keep the object 'alive' as long as the const-ref to it is alive.

For the gory details see Herb Sutter's brilliant article: Candidate for the most important const

LaszloG
Which does not help at all for return values. The lifetime of the reference is *at best* the end of the expression where the function call occurred. This is also an area where I would expect compilers to have a bug/creative interpretation of the standard.
Bart van Ingen Schenau
@Bart: With all due respect, please read the referenced article. Below is a short quote:This is a C++ feature… [...] Normally, a temporary object lasts only until the end of the full expression in which it appears. However, C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error. (...this only applies to stack-based references. It doesn’t work for references that are members of objects.)
LaszloG
as for " I would expect compilers to have a bug/creative interpretation of the standard", Herb writes:"Does this work in practice? Yes, it works on all compilers I tried (except Digital Mars 8.50, so I sent a bug report to Walter to rattle his cage :-) and he quickly fixed it for the Digital Mars 8.51.0 beta)."
LaszloG
@LaszloG: I have read the referenced article and it did not tell me anything new. When you *directly* initialise a const-reference with a temporary object, the lifetime of the object gets extended. But this property is *not* transitive, so any further references initialised from that first reference *do not* extend the lifetime any further. And how long does that reference which is returned from the function live exactly?
Bart van Ingen Schenau
Apart from my preceding comment, there is an explicit exception for temporary objects used in return statements: "A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits." (Source: C++ standard, clause 12.2/5). So, no creative interpretation was needed, it was explicitly spelled out in the standard: returning a temporary from a function *does not* extend the lifetime. (If this were not the case, a lot of compilers would have had a problem with the stack management)
Bart van Ingen Schenau
Bart, you're right, I stand corrected. I've mixed up the cases of returning a reference and returning a temp object and binding a reference to it in the caller. Thanks for clearing up this one.
LaszloG