Question about exact time of destruction of temporaries in C++
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 ?
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.
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.
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)
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()
.
Yes, it is safe, albeit illegal in the current form. You can work around the error by using an explicit intermediate cast to const-reference type
takesPointer( &(const Type &) getValue() );
This makes it perfectly legal as long as the temporary object is alive, which is till the end of evaluation of the full expression.
Moreover, you can even cast away the constness and modify the temporary object through the pointer (keeping in mind that it will be destroyed at the end of full expression). This is perfectly legal as long as the temporary object itself is not constant.
Using a comma operator, you can "stretch" full expressions, and thus write quite extensive sequences of operations that work with a "long-lived" temporary object
Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity
The practice is rather questionable though and most of the time there's no point in doing this.
精彩评论