- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前正在将我使用 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);
但这并没有解决我需要在每个项目中检查三元运算符(其中混合了左值和右值)的问题,我想在没有编译器任何帮助的情况下进行移植,因为它是一个运行时可能会或可能不会发生的问题。
我不明白的是,我对三元运算符的使用是否存在错误或不良做法?是否有更好的解决方案来检测这些案例?为什么我要手动复制一些对象来欺骗优化?这真的是有意为之的行为吗?在你的大部分代码库中都没有问题吗?你是如何处理这些问题的?
我现在对如何取得进展感到有点困惑,非常感谢任何建议和/或解释。谢谢!
我测试了以下两个有效的案例:
第一个示例看起来与我的情况类似,期望没有类实例用于存储全局字符串。 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 typeT1
can be converted to match an operand expressionE2
of typeT2
is defined as follows:
- If
E2
is an lvalue:E1
can be converted to matchE2
ifE1
can be implicitly converted to the type "lvalue reference toT2
", 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 matchE2
ifE1
can be implicitly converted to the type "rvalue reference toT2
", 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
andE2
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 matchE2
if the class ofT2
is the same type as, or a base class of, the class ofT1
, and the cv-qualification ofT2
is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification ofT1
. If the conversion is applied,E1
is changed to a prvalue of typeT2
by copy-initializing a temporary of typeT2
fromE1
and using that temporary as the converted operand.- Otherwise (i.e., if
E1
orE2
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 matchE2
ifE1
can be implicitly converted to the type that expressionE2
would have ifE2
were converted to a prvalue (or the type it has, ifE2
is a prvalue).
适用第四点,因此应自动生成拷贝,无需更改源代码。
在这两种情况下,在构建 retval
时都可以安全地 move 临时拷贝。
关于C++:三元运算符中使用的右值引用似乎破坏了现有代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14778326/
谁能帮我解决这个问题?我有一个 Tomcat 和简单的 JSF 应用程序:https://github.com/gooamoko/jsfbilling/ .当我在 Tomcat 上运行应用程序时,它运
我有两个这样的域类,第一个是 Manager : package com.mnm class Manager { String name; static hasMany = [ pro
当我运行以下代码时,打印输出似乎不正确。 void thread_Calc(int *pos) { printf("recieved %d\n", *pos); sig = -1; man
这个问题在这里已经有了答案: How to access a local variable from a different function using pointers? (10 个答案) 关闭
我编写了一个程序,其中列表构建器方法返回 IEnumerable of string,其中包括大量字符串(100 万个项目),我将其存储在 List of string 中,然后它将所有项目附加到 中
我正在尝试编写一个 IRC 类型的聊天客户端,它具有可以连接到服务器的客户端。我试图让它在本地 atm 上工作(使用 FIFOS 而不是套接字)。 我遇到了以下我似乎无法解决的问题: 接受新的客户端连
我的一个 cronjobs 每天发送一封电子邮件 35 6 * * * cd $EZPUBLISHROOT && $PHP runcronjobs.php -q 2>&1 我停止使用 cron sud
我使用 WPF 打印路径来处理在我们的应用程序中创建的大型图表。整个图表由视觉效果组成。 所谓的“DesignerPaginator”对图表进行分页(非常简单)。 从这一点来说,我做了以下三件事: -
我尝试在更新之前跟踪系统应用程序并使用: public static boolean isSystemApplication(Context ctx, IContent content) {
我在这里附上了一个查询分析结果,https://explain.depesz.com/s/x9BN 这是查询 EXPLAIN ANALYZE SELECT branche
我正在做一个 CXF(spring) 项目 (HUB)。部署后,我可以看到肥皂和休息服务列表,我通过两个地址打开它。一种是使用本地主机,第二种是使用我电脑的 ip。所以我得到了这些输出。 使用本地主机
这是一个 AnyHashable 不支持枚举转换的简单案例。 enum testEnum: String { case Test } let myObject: AnyHashable = t
我的主要目标是比较存储在数据库和 XLSX 文件中的数据。 为此,我按以下方式创建了两个列表: private class ProductList { public string produc
我从 CMake 3.6 更新到任何最新版本 (3.12.0-rc2),现在我的一个程序无法编译。 奇怪的是,错误消息显示了标准库本身中的 undefined symbol 。这是错误消息: Unde
我希望将我的自定义对话框动画化为从特定点出现,但我无法为对话框设置动画。 该对话框是一个基本的 RelativeLayout,设置为 extends Dialog 类中的布局。 正如这里的一些答案所建
我已经在这个论坛上调查过很多类似的问题,但似乎没有一个能解决我的问题。 我会在底部列出我在这个论坛上看到的一些问题页面,但让我先谈谈我对这个问题的看法。 我正在使用 codeigniter v 2.x
我正在尝试在 RHEL 7 上启动一个 docker-compose 项目作为 systemd 服务。这是我的 systemd 脚本 (/etc/systemd/system/wp.service):
这个问题已经有答案了: "Notice: Undefined variable", "Notice: Undefined index", "Warning: Undefined array key",
我正在尝试在 RHEL 7 上启动一个 docker-compose 项目作为 systemd 服务。这是我的 systemd 脚本 (/etc/systemd/system/wp.service):
此问题出现在my last question here之后。我想将每个按钮聚焦和失去焦点背景设置为主菜单(ContentPane 即 JPanel)下方的背景颜色,因此按钮看起来像选项卡。它在不同的环
我是一名优秀的程序员,十分优秀!