简体   繁体   English

我可以确保RVO用于reintrepret-cast'ed值吗?

[英]Can I ensure RVO for reintrepret-cast'ed values?

Suppose I've written: 假设我写了:

Foo get_a_foo() {
    return reinterpret_cast<Foo>(get_a_bar());
}

and suppose that sizeof(Foo) == sizeof(Bar) . 并假设sizeof(Foo) == sizeof(Bar)

Does return value optimization necessarily take place here, or are compilers allowed to do whatever they like when I "break the rules" by using a reinterpret_cast? 返回值优化是否必然发生在这里,或者当我通过使用reinterpret_cast“违反规则”时,编译器是否可以做任何他们喜欢的事情? If I don't get RVO, or am not guaranteed it - can I change this code to ensure that it occur? 如果我没有得到RVO,或者我不能保证它 - 我可以更改此代码以确保它发生吗?

My question is about C++11 and, separately, C++17 (since there was some change in it wrt RVO, if I'm not mistaken). 我的问题是关于C ++ 11,另外还有C ++ 17(因为如果我没有弄错的话,它在RVO中有一些变化)。

Suppose I've written: 假设我写了:

 Foo get_a_foo() { return reinterpret_cast<Foo>(get_a_bar()); } 

and suppose that sizeof(Foo) == sizeof(Bar) . 并假设sizeof(Foo) == sizeof(Bar)

That reinterpret_cast is not legal for all possible Foo and Bar types. 对于所有可能的FooBar类型, reinterpret_cast都不合法。 It only works for cases where: 它仅适用于以下情况:

  1. Bar is a pointer and Foo is either a pointer or an integer/enum big enough to hold pointers. Bar是一个指针, Foo可以是一个指针,也可以是一个足以容纳指针的整数/枚举。
  2. Bar is an integer/enum big enough to hold a pointer, and Foo is a pointer. Bar是一个足以容纳指针的整数/枚举,而Foo是一个指针。
  3. Bar is an object type and Foo is a reference type. Bar是对象类型, Foo是引用类型。

There are a couple of other cases I didn't cover, but they're either irrelevant ( nullptr_t casting) or fall under similar issues for #1 or #2. 还有一些我没有涉及的其他案例,但它们要么无关紧要( nullptr_t cast),要么属于#1或#2的类似问题。

See, elision doesn't actually matter when dealing in fundamental types. 看,elision在处理基本类型时实际上并不重要。 You can't tell the difference between eliding a copy/move of fundamental types and not eliding it. 你无法区分如何删除基本类型的复制/移动而不是忽略它。 So is there a conversion there? 那里有转换吗? Is the compiler just using the return value register? 编译器只是使用返回值寄存器吗? That's up to the compiler, via the "as if" rule. 这取决于编译器,通过“似乎”规则。

And elision doesn't apply when returning reference types, so #3 is out. 返回引用类型时,elision不适用,因此#3已经出局。

But if Foo and Bar are user-defined object types (or object types other than pointers, integers, or member pointers), the cast is is ill-formed . 但是,如果FooBar是用户定义的对象类型(或指针,整数或成员指针以外的对象类型),则转换不正确的 reinterpret_cast is not some kind of trivial memcpy conversion function. reinterpret_cast不是某种简单的memcpy转换函数。

So let's replace this with some code that could, you know, actually work: 所以,让我们用一些代码来代替它,你知道,这些代码实际上可以工作:

Foo get_a_foo()
{
    return std::bit_cast<Foo>(get_a_bar());
}

Where C++20's std::bit_cast effectively converts one trivial copyable type to another trivial copyable type. 其中C ++ 20的std::bit_cast有效地将一个普通的可复制类型转换为另一个普通的可复制类型。

That conversion still would not be elided. 转换仍然不会被遗漏。 Or at least, not in the way "elision" is typically used. 或者至少,不是通常使用“省略”的方式。

Because the two types are trivially copyable, and bit_cast will only call trivial constructors, the compiler could certainly erase the constructors, and even use the return value object of get_a_foo as the return value object of get_a_bar . 因为这两种类型都是可复制的,而bit_cast只会调用普通的构造函数,所以编译器当然可以擦除构造函数,甚至可以使用get_a_foo的返回值对象作为get_a_bar的返回值对象。 And thus, it could be considered "elision". 因此,它可以被认为是“省略”。

But "elision" typically refers to the part of the standard that allows the implementation to disregard even non-trivial constructor/destructors. 但是“省略”通常指的是标准中允许实现忽略甚至非平凡的构造函数/析构函数的部分。 The compiler can only perform the above because all of the constructors and destructors are trivial. 编译器只能执行上述操作,因为所有构造函数和析构函数都是微不足道的。 If they were non-trivial, they could not be disregarded (then again, if they were non-trivial, std::bit_cast wouldn't work ). 如果它们是非平凡的,那么它们就不会被忽视(那么,如果它们是非平凡的,那么std::bit_cast 将不起作用 )。

My point is that the optimization of the conversion above is not due to "elision" or RVO rules; 我的观点是,上述转换的优化不是由于“省略”或RVO规则; it's due entirely to the "as if" rule. 它完全归功于“似乎”规则。 Even in C++17, whether the bit_cast call is effectively made a noop is entirely up to the compiler. 即使在C ++ 17中, bit_cast调用是否有效地成为noop完全取决于编译器。 Yes, after having created the Foo prvalue, the "elision" of it's copy into the function's return value object is required by C++17. 是的,在创建了Foo prvalue之后,C ++ 17需要将它的副本“省略”到函数的返回值对象中。

But the conversion itself is not a matter of elision. 但转换本身并不是一个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM