c++传递给 const 引用的右值

发布于 2024-09-07 09:56:27 字数 633 浏览 7 评论 0 原文

我试图了解有关引用和右值的确切 C++(C++0x 之前)行为。以下内容有效吗?

void someFunc ( const MyType & val ) { 
    //do a lot of stuff
    doSthWithValue ( val);
} 

MyType creatorFunc ( ) { 
    return MyType ( "some initialization value" ); 
} 

int main () { 
    someFunc ( creatorFunc() ); 
    return 0; 
}

我在尝试修改的库中发现了类似的代码。我发现代码在 Visual Studio 2005 下崩溃。
我对上述内容的理解是,发生的事情是:
CreatorFunc 按值返回,因此创建了一个临时 MyType 对象 obj1。 (并保留......在堆栈上?) someFunc 正在引用该临时对象,并且随着计算的进行,临时对象将被覆盖/释放。
现在,令人难以置信的是代码大多数情况下都运行良好。更重要的是,用一段简单的代码我无法重现崩溃。
这里正在发生/应该发生什么?引用 (val) 是否为 const 有关系吗?从creatorFunc返回的对象的生命周期是多少?

I'm trying to understand exact C++ (pre C++0x) behavior with regards to references and rvalues. Is the following valid?

void someFunc ( const MyType & val ) { 
    //do a lot of stuff
    doSthWithValue ( val);
} 

MyType creatorFunc ( ) { 
    return MyType ( "some initialization value" ); 
} 

int main () { 
    someFunc ( creatorFunc() ); 
    return 0; 
}

I found similar code in a library I'm trying to modify. I found out the code crashes under Visual Studio 2005.
The way I understand the above, what is happening is:
creatorFunc is returning by value, so a temporary MyType object obj1 is created. (and kept... on the stack?)
someFunc is taking a reference to that temporary object, and as computation progresses the temporary object is overwritten/freed.
Now, what is mind-boggling is that the code most often works fine. What is more, with a simple piece of code I cannot reproduce the crash.
What is happening/supposed to happen here? Does is matter if the reference (val) is const or not? What is the lifespan of the object returned from creatorFunc?

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

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

发布评论

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

评论(6

ˉ厌 2024-09-14 09:56:27

返回值具有临时值的生命周期。在 C++ 中,这意味着创建类型的完整表达式,因此在调用 someFunc 返回之前不应调用 MyType 的析构函数。

我对你的“被覆盖/释放”很好奇。当然对这个对象调用delete是不行的;它存在于堆栈中,删除它可能会导致堆损坏。此外,覆盖/修改它也可能很糟糕。您的示例使用常量“C string”;在许多编译器上,像这样的值存储在只读内存中,因此稍后尝试修改它可能会导致崩溃/访问冲突。 (不过,我不确定 Visual C++ 是否执行此优化)。

通过 const 传递临时值与通过可变引用传递临时值之间存在很大差异。标准 C++ 不允许创建对临时对象的可变引用,并且大多数编译器(包括 GCC)都会拒绝它,但至少某些版本的 Visual C++ 允许这样做。

如果您使用可变引用传递它,您想要编写的是:

   MyType t = creatorFunc();
   someFunc(t);

The return value has the lifetime of a temporary. In C++ that means the complete expression that created the type, so the destructor of MyType shouldn't be called until after the call to someFunc returns.

I'm curious at your 'is overwritten/freed'. Certainly calling delete on this object is not OK; it lives on the stack and deleting it would probably cause heap corruption. Also, overwriting/modifying it could also be bad. Your example uses a constant "C string"; on many compilers values like this are stored in read-only memory, so attempting to modify it later could cause a crash/access violation. (I'm not sure if Visual C++ does this optimization, however).

There is a big difference between passing a temporary by const versus mutable references. Creating a mutable reference to a temporary is not allowed by standard C++, and most compilers (including GCC) will reject it, though at least some versions of Visual C++ do allow it.

If you are passing it with a mutable reference, what you want to write is:

   MyType t = creatorFunc();
   someFunc(t);
随风而去 2024-09-14 09:56:27

creatorFunc() 创建的临时变量的生命周期是到 someFunc 调用结束为止。实际上,下一个序列点(宽松地,分号)。

someFunc 正在引用该临时对象,并且随着计算的进行,临时对象将被覆盖/释放”

听起来好像 someFunc 正在做“坏事”。您不应该覆盖或释放以下对象:由const&传递。

The lifetime of the temporary created by creatorFunc() is until the end of the someFunc call. Effectively, the next sequence point (loosely, the semicolon).

someFunc is taking a reference to that temporary object, and as computation progresses the temporary object is overwritten/freed"

It sounds like someFunc is doing "bad things". You should not be overwriting or freeing an object that is passed by const&.

弥繁 2024-09-14 09:56:27

通常,临时对象(例如函数调用返回的对象)的生命周期可以延伸到“封闭表达式”的末尾。然而,临时绑定到引用的生命周期通常会“提升”到引用的生命周期。

因此,传递给 someFunc() 的临时变量应该保持活动状态并可访问,直到 someFunc() 返回。但是,如果 someFunc() (或任何它可能调用的内容,例如 doSthWithValue())隐藏了对 val 的指针或引用,例如在集合或其他对象中,为了稍后使用,临时对象将不再存在,并且您可能会在尝试使用它时崩溃。这可能就是为什么您看到引用临时对象的简单代码没有崩溃,而更复杂的代码会崩溃。

有关更多详细信息,请参阅以下项目:

从函数返回值(不是引用),绑定到调用函数中的 const 引用;它的生命周期如何扩展到调用函数的范围?
C++ 常量引用生命周期(容器适配器)

另请注意,该标准允许临时变量仅绑定到 const 引用,但正如 Jack Lloyd 提到的 MSVC 的某些版本(根据 http://msdn.microsoft.com/en-us/library/cfbk5ddc.aspx)允许您将它们绑定到非常量引用。然而,在快速测试中,我发现VS 2010的编译器仍然允许临时变量绑定到非常量引用。

Normally a temporary object (such as one returned by a function call) has a lifetime that extends to the end of the "enclosing expression". However, a temporary bound to a reference generally has it's lifetime 'promoted' to the lifetime of the reference.

So the temporary being passed to someFunc() should remain alive and accessible until after someFunc() returns. However, if someFunc() (or whatever it might call, such as doSthWithValue()) stashes away a pointer or reference to val, for example in a collection or some other object, for use at some later time, the temporary object will no longer be alive and you will likely crash trying to use it. That might be why you seee no crash in simple code taking a reference to a temporary, while more complex code crashes.

See the following items for more details:

return value (not a reference) from the function, bound to a const reference in the calling function; how is its lifetime extended to the scope of the calling function?
C++ constant reference lifetime (container adaptor)

Also note that the standard allows temporaries to be bound only to const references, but as Jack Lloyd mentioned some versions of MSVC (prior to VS 2003 according to http://msdn.microsoft.com/en-us/library/cfbk5ddc.aspx) allow you to bind them to non-const references. However, in a quick test, I find that VS 2010's compiler still allows temporaries to be bound to non-const references.

眼眸 2024-09-14 09:56:27

您只能将临时引用绑定到 const 引用。

You can only bind a temporary to a const reference.

迷荒 2024-09-14 09:56:27

是的,引用是 const 很重要。您不能将临时引用绑定到非常量引用,因此代码将无法编译。

除此之外,您的代码定义良好并且将按预期工作。

Yes, it matters that the reference is const. You cannot bind a temporary to a non-const references, so the code would not compile otherwise.

Apart from that, your code is well-defined and will work as expected.

北渚 2024-09-14 09:56:27

我也遇到过同样的问题,当我在 SO 上发表评论时,因为之前提到过而受到了批评。我觉得其他人也有这个问题是正确的!

我还在使用VS 2005 (SP1),也许有一些编译器优化错误?

来自 creatorFunc() 的结果似乎对于调用 someFunc (creatorFunc() ); 来说并没有保持活动状态,我发现要做的唯一一件事就是将其分成两行从而删除临时变量。

I've had the same issue, and when I commented as such on SO got hammered for mentioning it before. I feel vindicated somebody else has this issue!!

I'm also still using VS 2005 (SP1), perhaps some compiler optimization error?

The result from creatorFunc() doesn't appear to remain alive for the call someFunc ( creatorFunc() ); the only thing I found to do was split this into 2 lines thus removing the temp variable.

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