关于C ++中临时破坏的确切时间的问题

时间:2010-02-25 13:57:42

标签: c++ pointers temporary destruction

是以下代码安全(它在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”返回之后,还是在被调用之后它会被销毁?

5 个答案:

答案 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

虽然这种做法值得怀疑,但大部分时间都没有意义。