gpt4 book ai didi

C++:三元运算符中使用的右值引用似乎破坏了现有代码

转载 作者:太空狗 更新时间:2023-10-29 21:02:48 25 4
gpt4 key购买 nike

我目前正在将我使用 Borland C++-Builder 5 和 6 开发多年的项目之一移植到最新的 Embarcadero C++-Builder XE 3 Update 2。XE 3 支持一些新的 C+ +11-诸如右值引用之类的东西对我来说当然是全新的,因为前者使用的是非常古老的编译器。我只需要很少的修改就可以使我的项目可编译,但在运行时我遇到了一个问题,这似乎是新右值引用和 move 语义的结果。

我有一个类,它有一个 std::wstring 类型的字段,存储一个路径,该路径只能从一个方法中读取,该路径在三元运算符中使用该字段,如下所示:

std::wstring retVal = someCondition ? this->classField : Util::doSomething(someArg);

someCondition 只是对 std::wstring.empty() 的调用,Util::doSomething 返回 std::wstring 作为值,没有引用或其他涉及,只是复制数据。

对于 XE 3,在第一次将 someCondition 评估为真后,retVal 会正确填充 classField 的内容,但之后 classField 的内容为空。使用调试器,我可以跟踪执行优化的赋值运算符和右值引用:

 #if _HAS_RVALUE_REFERENCES
[...]
_Myt& operator=(_Myt&& _Right)
{ // assign by moving _Right
return (assign(_STD forward<_Myt>(_Right)));
}

_Myt& assign(_Myt&& _Right)
{ // assign by moving _Right
[...]

我读到的关于右值引用的内容可以完美地解释我的问题,我什至发现了两条评论来解释为什么我的 classField 被视为右值。

https://stackoverflow.com/a/8535301/2055163

https://stackoverflow.com/a/6957421

我可以用一份额外的 classField 手动拷贝修复上面的行:

std::wstring retVal = someCondition ? std::wstring(this->classField) : Util::doSomething(someArg);

但这并没有解决我需要在每个项目中检查三元运算符(其中混合了左值和右值)的问题,我想在没有编译器任何帮助的情况下进行移植,因为它是一个运行时可能会或可能不会发生的问题。

我不明白的是,我对三元运算符的使用是否存在错误或不良做法?是否有更好的解决方案来检测这些案例?为什么我要手动复制一些对象来欺骗优化?这真的是有意为之的行为吗?在你的大部分代码库中都没有问题吗?你是如何处理这些问题的?

我现在对如何取得进展感到有点困惑,非常感谢任何建议和/或解释。谢谢!


我测试了以下两个有效的案例:

http://ideone.com/mWxxK3

第一个示例看起来与我的情况类似,期望没有类实例用于存储全局字符串。 dummy2 已正确填充,dummy 保留其内容。

std::wstring retVal = someCondition ? this->classField : doSomethingResult;

当我更改上面的行以通过在使用三元运算符之前将 Util:... 的结果保存到 std::wstring 来删除右值时,一切都按预期进行。 retVal 有它的内容,this->classField 也有它的内容。

现在有什么结论? :-/

最佳答案

看起来像是一个编译器错误。标准的相关部分是 5.16p6:

[If] The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.


如果 Util::doSomething(someArg) 返回 std::string&& 而不是一个值,我们需要第 5.16p3 节:

Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class type, or if both are glvalues of the same value category and the same type except for cv-qualification, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:

  • If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted to the type "lvalue reference to T2", subject to the constraint that in the conversion the reference must bind directly to an lvalue.
  • If E2 is an xvalue: E1 can be converted to match E2 if E1 can be implicitly converted to the type "rvalue reference to T2", subject to the constraint that the reference must bind directly.
  • If E2 is an rvalue or if neither of the conversions above can be done and at least one of the operands has (possibly cv-qualified) class type:
    • if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of, the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to a prvalue of type T2 by copy-initializing a temporary of type T2 from E1 and using that temporary as the converted operand.
    • Otherwise (i.e., if E1 or E2 has a nonclass type, or if they both have class types but the underlying classes are not either the same or one a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to a prvalue (or the type it has, if E2 is a prvalue).

适用第四点,因此应自动生成拷贝,无需更改源代码。


在这两种情况下,在构建 retval 时都可以安全地 move 临时拷贝。

关于C++:三元运算符中使用的右值引用似乎破坏了现有代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14778326/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com