[英]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(因為如果我沒有弄錯的話,它在RVO中有一些變化)。
假設我寫了:
Foo get_a_foo() { return reinterpret_cast<Foo>(get_a_bar()); }
並假設
sizeof(Foo) == sizeof(Bar)
。
對於所有可能的Foo
和Bar
類型, reinterpret_cast
都不合法。 它僅適用於以下情況:
Bar
是一個指針, Foo
可以是一個指針,也可以是一個足以容納指針的整數/枚舉。 Bar
是一個足以容納指針的整數/枚舉,而Foo
是一個指針。 Bar
是對象類型, Foo
是引用類型。 還有一些我沒有涉及的其他案例,但它們要么無關緊要( nullptr_t
cast),要么屬於#1或#2的類似問題。
看,elision在處理基本類型時實際上並不重要。 你無法區分如何刪除基本類型的復制/移動而不是忽略它。 那里有轉換嗎? 編譯器只是使用返回值寄存器嗎? 這取決於編譯器,通過“似乎”規則。
返回引用類型時,elision不適用,因此#3已經出局。
但是,如果Foo
和Bar
是用戶定義的對象類型(或指針,整數或成員指針以外的對象類型),則轉換是不正確的 。 reinterpret_cast
不是某種簡單的memcpy
轉換函數。
所以,讓我們用一些代碼來代替它,你知道,這些代碼實際上可以工作:
Foo get_a_foo()
{
return std::bit_cast<Foo>(get_a_bar());
}
其中C ++ 20的std::bit_cast
有效地將一個普通的可復制類型轉換為另一個普通的可復制類型。
轉換仍然不會被遺漏。 或者至少,不是通常使用“省略”的方式。
因為這兩種類型都是可復制的,而bit_cast
只會調用普通的構造函數,所以編譯器當然可以擦除構造函數,甚至可以使用get_a_foo
的返回值對象作為get_a_bar
的返回值對象。 因此,它可以被認為是“省略”。
但是“省略”通常指的是標准中允許實現忽略甚至非平凡的構造函數/析構函數的部分。 編譯器只能執行上述操作,因為所有構造函數和析構函數都是微不足道的。 如果它們是非平凡的,那么它們就不會被忽視(那么,如果它們是非平凡的,那么std::bit_cast
將不起作用 )。
我的觀點是,上述轉換的優化不是由於“省略”或RVO規則; 它完全歸功於“似乎”規則。 即使在C ++ 17中, bit_cast
調用是否有效地成為noop完全取決於編譯器。 是的,在創建了Foo
prvalue之后,C ++ 17需要將它的副本“省略”到函數的返回值對象中。
但轉換本身並不是一個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.