3

以下代码是否安全(它在调试中工作):

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”(它是库的一部分),我只能将其包装在调用 takePointer 的函数“takesReference”中 - 这会消除副本,还是允许编译器创建一个副本(“类型”是一个 int-3x3-Matrix,所以它不会那么糟糕,但仍然......)?

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

关于销毁时间:它会在“takesPointer”返回之后被销毁,还是在它被调用之后被销毁?

4

5 回答 5

10

正如其他答案所述,您不能使用临时地址。但是,如果您更改

void takesPointer(const Type* v);

void takesPointer(const Type& v);

那么下面的代码应该在没有警告的情况下编译:

takesPointer(getValue());

因为您可以将临时对象绑定到 const 引用,并且它应该可以正常工作。

于 2010-02-25T14:28:04.533 回答
7

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

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

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

于 2010-02-25T14:03:32.233 回答
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)

于 2010-02-25T14:13:32.253 回答
0

您可以将非 const 右值绑定到 const 引用左值,但您将其绑定到 const 指针左值。

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

于 2010-02-25T14:01:45.370 回答
0

是的,它是安全的,尽管在当前形式下是非法的。您可以通过使用显式中间转换为 const-reference 类型来解决该错误

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

只要临时对象还活着,这使得它完全合法,直到完整表达式的评估结束。

此外,您甚至可以抛弃常量并通过指针修改临时对象(请记住,它将在完整表达式结束时被销毁)。只要临时对象本身不是常量,这是完全合法的。

使用逗号运算符,您可以“拉伸”完整的表达式,从而编写相当广泛的操作序列来处理“长期存在的”临时对象

Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity

这种做法是相当值得怀疑的,而且大多数时候这样做没有意义。

于 2010-02-25T15:02:07.430 回答