我能否确保 RVO 用于重新转换的值?
Can I ensure RVO for reintrepret-cast'ed values?
假设我写了:
Foo get_a_foo() {
return reinterpret_cast<Foo>(get_a_bar());
}
并假设sizeof(Foo) == sizeof(Bar)
.
返回值优化是否必须在这里进行,或者当我使用 reinterpret_cast "违反规则"时,编译器是否可以做任何他们喜欢的事情?如果我没有得到 RVO,或者不能保证它 - 我可以更改此代码以确保它发生吗?
我的问题是关于 C++11 和单独的 C++17(如果我没记错的话,它在 r.r.t. RVO 中有一些变化)。
假设我写了:
Foo get_a_foo() { return reinterpret_cast<Foo>(get_a_bar()); }
并假设
sizeof(Foo) == sizeof(Bar)
.
该reinterpret_cast
对所有可能的Foo
和Bar
类型都不合法。它仅适用于以下情况:
Bar
是一个指针,Foo
是一个指针或一个足够大的整数/枚举,以容纳指针。Bar
是一个足够大的整数/枚举,可以容纳指针,Foo
是一个指针。Bar
是对象类型,Foo
是引用类型。
还有其他一些我没有介绍的情况,但它们要么无关紧要(nullptr_t
铸造),要么属于#1或#2的类似问题。
看,在处理基本类型时,省略实际上并不重要。您无法区分省略基本类型的复制/移动和不省略它之间的区别。那么那里有转换吗?编译器是否仅使用返回值寄存器?这取决于编译器,通过"好像"规则。
并且 elision 在返回引用类型时不适用,因此 #3 已退出。
但是,如果Foo
和Bar
是用户定义的对象类型(或指针、整数或成员指针以外的对象类型),则强制转换格式不正确。reinterpret_cast
不是某种微不足道的memcpy
转换函数。
因此,让我们用一些可以实际工作的代码来替换它:
Foo get_a_foo()
{
return std::bit_cast<Foo>(get_a_bar());
}
其中C++20std::bit_cast
有效地将一个平凡的可复制类型转换为另一个平凡的可复制类型。
这种转变仍然不会被取消。或者至少,不是通常使用"省略"的方式。
因为这两种类型是平凡可复制的,bit_cast
只会调用平凡构造函数,所以编译器当然可以擦除构造函数,甚至使用get_a_foo
的返回值对象作为get_a_bar
的返回值对象。因此,它可以被认为是"省略"。
但是"elision"通常是指标准中允许实现忽略甚至不平凡的构造函数/析构函数的部分。编译器只能执行上述操作,因为所有构造函数和析构函数都是微不足道的。如果它们是非平凡的,它们就不能被忽视(再说一次,如果它们是非平凡的,std::bit_cast
是行不通的)。
我的观点是,上述转换的优化不是由于"省略"或RVO规则;它完全是由于"好像"规则。即使在 C++17 中,bit_cast
调用是否有效地进行 noop 也完全取决于编译器。是的,在创建Foo
prvalue 后,C++17 需要将其复制到函数的返回值对象中的"省略"。
但皈依本身并不是一个消除的问题。
- C++通常的算术转换不转换
- 将图像魔术转换命令转换为魔术++c++代码
- 检查是否需要 utf8 转换并转换为 utf8
- 静态强制转换允许转换对象指针,但不允许转换整数
- 管理到本机值类转换:强制转换指针是否安全?
- 使用递归前缀转换前缀转换
- FFMpeg与OpenCV的格式转换/简单转换
- 转换操作员 转换构造函数=不直觉的行为
- c++多态性:基类的上转换/下转换和容器,缺少数据
- 如何将转换函数转换为lambda表达式
- 将指针 (T*) 强制转换或转换为两个常量 (T 常量 * 常量) 指针
- 如何在模板中的类型之间进行转换并转换回原始类型
- 比较双精度和整数,不进行转换或转换
- 如何将 CString 转换或转换为 LPWSTR
- 将新C++转换为旧C++
- 无法转换参数-转换丢失限定符
- 词法转换部分转换-有可能吗
- 如何转换tf::转换为btTransform
- 可接受的编程实践.转换和转换
- 两个指针之间的转换/强制转换