簡體   English   中英

如何確保執行 RVO 而不是復制?

[英]How can I ensure RVO instead of copy is performed?

在許多情況下,我想創建一個新的數據實例並將其返回給 API 調用方。

我了解到unique_ptr / shared_ptr可用於工廠模式(例如, 工廠模式在 c++ 中使用 unique_ptr

同時,我了解到在許多編譯器中都可以進行返回值優化 (RVO)(例如, 在 c++ 中返回 std::vector 的有效方法)。

我更喜歡 RVO,因為它更容易使用返回值而不用包裝unique_ptr並且更容易閱讀代碼,但是,由於無法保證 RVO,我不想意外犧牲性能並且必須使用unique_ptr來確保返回值是move d 而不是復制。

是否有任何方法可以明確指定要移動的返回值,以便在 RVO 可能的情況下它不會抱怨任何內容,或者如果 RVO 不可能,它將觸發一些編譯器警告? 如果這是可能的,我可以安全地擺脫在這種情況下返回 unique_ptr 的情況。

我使用的是 C++17,需要在 macOS 上支持 Apple Clang 11.0,在 Linux 上支持 g++ 9。

編輯:

我仍在學習 C++ 並且在發布此問題時沒有區分 RVO(返回值優化)和 NRVO(命名返回值優化)。 在我看來 NRVO 在像工廠方法這樣的模式中更常見和有用,例如:

vector<foo> vec;
// populate data into vec
return vec;

我正在尋找類似return std::move_only(returned_value) ,如果這個值不能移動(不是復制移動),它會給我一個編譯器警告。 也許我應該重新表述我的問題:如果不能保證 NRVO,為什么“按值返回”仍然是這個問題中的推薦方式( 在 c++ 中返回 std::vector 的有效方法),答案不應該是“這取決於”您的功能實現以及您是否可以接受意外的性能成本?

如何確保執行 RVO 而不是復制?

從 C++17 開始,該語言已經為您做到了這一點。 如果你有一個像

T foo() { /*stuff*/; return T{ /*stuff*/ }; }

由於保證復制省略,返回的對象保證被省略。

如果你有一個像

T foo() 
{
    T obj{ /*stuff*/ }; 
    // do stuff with obj
    return obj;
}

然后你會得到不保證的 NRVO(命名返回值優化),或者編譯器會移動obj因為標准中有一條規則,所有具有自動存儲持續時間的函數本地對象將被移出函數,如果它們有一個移動構造函數。

這意味着您將獲得副本的唯一時間是您正在返回一個無法優化的對象(它是一個命名的本地對象或者它是一個函數參數)並且它不支持移動。 全局對象總是被復制,因為它們不限於函數。

我更喜歡 RVO 因為它更容易使用返回值而不用包裝 unique_ptr

如果 NRVO 不可能,則不能在沒有 RVO、NRVO 或隱式移動的情況下返回 unique_ptr。 不可復制:

std::unique_ptr<int> ptr1;
std::unique_ptr<int> ptr2;
ptr2 = ptr1; // error: not copyable

這不編譯。 如果不是 RVO、NRVO 或 move,這也不會編譯:

std::unique_ptr<int> foo()
{
    return std::unique_ptr<int>{};
}

在這種情況下,這是由於 C++17 的保證 RVO。 但即使沒有 RVO,你仍然會得到一個移動而不是一個副本。

如果不是 NRVO 或保證移動回退,這將無法編譯:

std::unique_ptr<int> foo()
{
    std::unique_ptr<int> ptr;
    return ptr;
}

所以你已經在依賴 RVO、NRVO 或移動。 不需要 unique_ptr。 如果您的類型是可移動的,您可以確保即使在 NRVO 不可能的情況下也不會執行任何副本,例如並非所有return語句都返回相同的本地對象:

std::unique_ptr<int> foo(const bool flag)
{
    if (flag) {
        std::unique_ptr<int> ptr1;
        return ptr; // implicit move
    }
    std::unique_ptr<int> ptr2;
    return ptr2; // implicit move
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM