关于C++中临时销毁的确切时间的问题

发布于 2024-08-23 15:53:12 字数 824 浏览 13 评论 0原文

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

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 - 这会消除副本,还是仍允许编译器创建一个副本(“类型”是一个 int-3x3-Matrix,所以它不会那么糟糕,但仍然......)?

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

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

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怎言笑 2024-08-30 15:53:12

正如其他答案所述,您不能获取临时地址。 的签名更改

void takesPointer(const Type* v);

但是,如果您将

void takesPointer(const Type& v);

为,则以下代码应该在编译时不会出现警告:

takesPointer(getValue());

因为您可以将临时值绑定到 const 引用,并且它应该以相同的方式工作。

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.

月依秋水 2024-08-30 15:53:12

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

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

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

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.

笑叹一世浮沉 2024-08-30 15:53:12

这将防止复制*和编译。

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)

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)

爱的那么颓废 2024-08-30 15:53:12

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

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

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

拧巴小姐 2024-08-30 15:53:12

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

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

但这种做法相当有问题,而且大多数时候没有意义在这样做的过程中。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文