views:

152

answers:

5

Hi, is the following code safe (it works in DEBUG) :

void takesPointer(const Type* v);//this function does read from v, it doesn't alter v in any way
Type getValue();
...
takesPointer(&getValue());//gives warning while compiling "not an lvalue"
...
Type tmp = getValue();
takesPointer(&tmp);//this is safe, and maybe I should just do it, instead of posting here

so - is it safe ? should I just forget about it and use the code with the explicit tmp ?

but anyways - I'm still interested if the optimizer is allowed to kill the temporary before returning from this call :

takePointer(&getValue())

EDIT: thank you all ! unfortunately I can't change the function "takesPointer" (it's part of a library), I could only wrap it in a function "takesReference", which calls takesPointer - would this eliminate the copy, or would the compiler still be allowed to create a copy (the "Type" is a int-3x3-Matrix, so it wouldn't be THAT bad, but still...) ?

inline void takesReference(const Type& v){ takesPointer(&v); }

About the time of destruction : will it be destroyed after "takesPointer" RETURNS, or after it's CALLED ?

A: 

You are allowed to bind a non-const rvalue to a const reference lvalue, but you're binding it to a const pointer lvalue.

And no, the optimzier can't destruct the result of getValue() before calling takePointer().

Bill
+6  A: 

The Standard forbids you to do &getValue() - exactly because it's not an lvalue. Ordinarily, if this was allowed, then the temporary resulting from that function call will live until the outer function returns and every other thing in the whole expression has completed being processed. This can be called "destroying temporaries after end of full-expression", and ensures things like the following works as expected

// the temporary string is alive until the whole expression has been processed
cout << string("hello");

The compiler gives you a diagnostic - that's all the Standard requires for ill-formed code. It doesn't force the compiler to abort compilation, for instance. But after code being ill-formed was diagnosed, the compiler can do everything it wants. So if you want to know what the compiler does in your case, you should read its manual.

Johannes Schaub - litb
+1  A: 

This will prevent copies* and compiles.

const Type& tmp = getValue(); 
takesPointer(&tmp);

Prevent copies is a bit strong because the compiler will often do this for you. You have to have access to the copy constructor but the compiler will often not use it:

#include "iostream"
class Type
{
public:
    explicit Type(int val) : m_val(val) { std::cout << "ctor";};
    Type(const Type& copy)
    {
        std::cout << "copy";
    };
private:
    int m_val;
};

Type getValue() { Type r(0); return r;};
void takesPointer(const Type* const)
{

};

int main(int argc, char* argv[])
{
    const Type tmp = getValue(); 
    takesPointer(&tmp);
}

Will print only "ctor" in release and "ctorcopy" in debug. (MVS2005)

Charles Beattie
Don;t want to steal your thunder, so you may want to mention why this works!
Martin York
"This will prevent copies" - it won't. The compiler can still create copies.
Johannes Schaub - litb
Thanks martin. Storing a const reference to an object will maintain the life of the result of the function until the reference is out of scope.
Charles Beattie
@Johannes: What's this business about binding a reference resulting in a copy?
Potatoswatter
@Potatuswatter, it's binding a reference to a *temporary* (more precisely, to an rvalue) that is potentially resulting in a copy. Temporaries have value character, so copying them isn't all that weird. Binding references to lvalues (which you may generally see as objects with a name) does *not* result in a copy, of course. To my knowledge, the rule was made to simplify implementations, but it was noticed that if you write a function like `Class }` and bind a reference to `Class().get();`, the compiler must already be able to handle it without copies, so C++0x changes it
Johannes Schaub - litb
+8  A: 

As other answers have stated you cannot take the address of a temporary. However, if you change the signature of

void takesPointer(const Type* v);

to

void takesPointer(const Type& v);

then the following code should compile without warnings:

takesPointer(getValue());

because you are allowed to bind a temporary to a const reference, and it should work just the same.

AshleysBrain
+1 Good point :)
Johannes Schaub - litb
A: 
AndreyT
"Moreover, you can even cast away the constness and modify the temporary object through the pointer" - Sadly that is not allowed in C++03, because the compiler is allowed to create a copy of the temporary and bind the reference to that copy. If it does, it is required to create a copy of type `const Type` (i.e cv-qualifiers come from the reference and the type comes from the temporary. There is an exlicit `[sic]` in the Standard about that).
Johannes Schaub - litb
@litb: Thanks for the correction. I was wondering about the legality of this for a while.
AndreyT