当右值对象作为函数调用的一部分访问其成员时被销毁

When do rvalue objects get destroyed when accessing their members as part of a function call?

本文关键字:成员 访问 一部分 对象 函数调用      更新时间:2023-10-16

我一直在考虑下面这段代码:

    PerformConflict(m_dwSession, 
        CONFLICT_DETECTED, 
        item.GetConflictedFile().GetUnNormalizedPath().c_str(), 
        item.GetSuggestedFile().GetUnNormalizedPath().c_str());
  • GetConflictFile()返回一个对象。
  • GetUnNormalizedPath()返回std::wstring
  • c_str()仅返回const wchar_t*(在本例中为右值std::wstring的内容)

我的问题是:规范中是否有任何东西保证这段代码是安全的?也就是说,所有的右值对象保证没有被销毁的时候,c_str()是得到一个指针到他们的内容?

这些临时变量将在它们所在的完整表达式结束时销毁。在您的例子中,这是您发布的整个代码片段。

这绝对没问题,只要你只在函数调用中使用const wchar_t*。如果你把它存储在任何地方,并试图在呼叫退出后访问它,你将被推入UB的深黑洞。

相关标准报价是(强调我的):

N3337 [class.temporary]/3:当实现引入具有非平凡构造函数(12.1)的类的临时对象时,12.8),它应确保为临时对象调用构造函数。类似地,析构函数应为用非平凡析构函数调用临时函数(12.4)。临时对象在最后一步被销毁在计算(词法上)包含创建它们的点的完整表达式(1.9)时。这是真的即使该求值以抛出异常结束。销毁的值计算和副作用临时对象只与完整表达式相关联,而不与任何特定的子表达式相关联。

如Herb Sutter所示,右值在其出现的表达式末尾被销毁。但是,如果将它们绑定到"对堆栈上const的引用",则它们的生存期将延长到引用的生存期。

基本上,如果你的函数有这样的签名:

PerformConflict(...,
                ...,
                const std::string& str1, //< any rvalue passed here will have the same lifetime as str1
                const std::string& str2  //< any rvalue passed here will have the same lifetime as str2
);

您应该能够在PerformConflict() 中操作字符串而不会出现问题。

PS:如果您按值传递参数(即const std::string str1)

这个问题也可以解决。