2010-02-25 72 views
3

是下面的代码安全(它在DEBUG):问题有关的临时破坏的确切时间C++

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()) 

编辑: 谢谢大家! 不幸的是我不能改变函数“takesPointer”(它是一个库的一部分),我只能将它包装在一个函数“takesReference”中,它调用takesPointer函数 - 是否会消除副本,还是允许编译器创建一个副本(“Type”是一个int-3x3-Matrix,所以它不会那么糟糕,但仍然...)?

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

关于销毁时间:它会在“takePointer”RETURNS后还是在它被调用之后被销毁?

+0

'Type'对象将在包含'takesReference'的表达式完成后被销毁。 – 2015-01-29 01:43:03

回答

0

您可以将一个非const rvalue绑定到一个const引用左值,但是您将它绑定到一个const指针左值。

并且不,在调用takePointer()之前,优化器不能破坏getValue()的结果。

7

该标准禁止你做&getValue() - 正是因为它不是左值。通常,如果允许此,则该函数调用所产生的临时值将一直存在,直到外部函数返回并且整个表达式中的其他所有内容都已完成处理。这可以被称为“全表达结束后销毁临时工”,并确保类似下面的工作的事情如预期

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

编译器为您提供了诊断 - 这是所有标准要求的形成不良的代码。例如,它不会强制编译器中止编译。但是,在诊断出代码格式不正确后,编译器可以做它想做的一切。所以如果你想知道编译器在你的情况下做什么,你应该阅读它的手册。

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); 
} 

将在调试打印仅释放“构造函数”和“ctorcopy”。 (MVS2005)

+0

不要窃取你的雷霆,所以你可能想提一下它为什么可以工作! – 2010-02-25 14:33:22

+1

“这将防止副本” - 它不会。编译器仍然可以创建副本。 – 2010-02-25 15:21:29

+0

感谢马丁。将一个const引用存储到一个对象将维持该函数结果的有效期,直到该引用超出范围。 – 2010-02-26 09:57:42

10

正如其他答案已经声明,你不能采取临时地址。但是,如果你改变

void takesPointer(const Type* v); 

的签名

void takesPointer(const Type& v); 

然后将下面的代码应编译没有警告:

takesPointer(getValue()); 

,因为你被允许绑定一个临时的常量参考,它应该工作一样。

+0

+1好点:) – 2010-02-25 15:21:49

0

是的,这是安全的,虽然目前的形式是非法的。您可以通过使用一个明确的中间铸为const引用类型

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 

的做法是相当值得怀疑,但并大多数情况下,这样做没有意义。

+0

“此外,你可以甚至丢弃const并通过指针修改临时对象“ - 遗憾的是,在C++ 03中不允许,因为允许编译器创建临时副本并将引用绑定到该副本。如果存在,则需要创建一个'const Type'类型的副本(即cv-qualifiers来自引用,类型来自临时文件。标准中有一个明确的'[sic]')。 – 2010-02-25 15:20:12

+0

@litb:感谢您的更正。我想知道这一段时间的合法性。 – AnT 2010-02-25 16:55:00