是以下代码安全(它在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
所以 - 这样安全吗?我应该忘记它并使用带有显式tmp的代码吗?
但无论如何 - 如果允许优化器在从此调用返回之前杀死临时符,我仍然感兴趣:
takePointer(&getValue())
编辑: 谢谢你们 ! 不幸的是我无法更改函数“takePointer”(它是库的一部分),我只能将它包装在一个函数“takeReference”中,它调用takePointer - 这会消除副本,还是编译器仍然可以创建一个副本(“类型”是一个int-3x3-Matrix,所以它不会那么糟糕,但仍然......)?
inline void takesReference(const Type& v){ takesPointer(&v); }
关于破坏的时间:在“takePointer”返回之后,还是在被调用之后它会被销毁?
答案 0 :(得分:10)
正如其他答案所述,你不能拿一个临时的地址。但是,如果您更改
的签名void takesPointer(const Type* v);
到
void takesPointer(const Type& v);
然后下面的代码应该在没有警告的情况下编译:
takesPointer(getValue());
因为您可以将临时绑定到const引用,它应该可以正常工作。
答案 1 :(得分:7)
标准禁止你做&getValue()
- 完全是因为它不是左值。通常,如果允许 ,那么该函数调用产生的临时函数将一直存在,直到外部函数返回并且整个表达式中的所有其他内容都已完成处理。这可以被称为“在完全表达结束后摧毁临时值”,并确保以下内容按预期工作
// the temporary string is alive until the whole expression has been processed
cout << string("hello");
编译器为您提供诊断 - 这是标准对不良格式代码的要求。例如,它不会强制编译器中止编译。但是在诊断出代码不正确之后,编译器可以完成它想要的任何事情。因此,如果您想知道编译器在您的情况下做了什么,您应该阅读其手册。
答案 2 :(得分:1)
这将阻止复制*和编译。
const Type& tmp = getValue();
takesPointer(&tmp);
防止副本有点强,因为编译器通常会为您执行此操作。 您必须有权访问复制构造函数,但编译器通常不会使用它:
#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);
}
将在发布中仅打印“ctor”,在调试中打印“ctorcopy”。 (MVS2005)
答案 3 :(得分:0)
您可以将非const rvalue绑定到const引用左值,但是您将它绑定到const指针左值。
不,在调用getValue()
之前,优化器无法破坏takePointer()
的结果。
答案 4 :(得分:0)
是的,虽然目前的形式是非法的,但它是安全的。您可以通过使用显式中间转换为const-reference类型
来解决错误takesPointer( &(const Type &) getValue() );
只要临时对象处于活动状态,这就完全合法,直到完整表达式的评估结束。
此外,您甚至可以抛弃const并通过指针修改临时对象(请记住它将在完整表达式结束时被销毁)。只要临时对象本身不是常量,这是完全合法的。 德尔>
使用逗号运算符,您可以“拉伸”完整的表达式,从而编写与“长期存在的”临时对象一起使用的大量操作序列
Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity
虽然这种做法值得怀疑,但大部分时间都没有意义。