C++複製省略與回傳值

最後更新: 2024-11-03 19:25:13 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

複製省略允許實作即使複製建構函式或移動建構函式具有可觀察的副作用,也省略複製建構或移動建構。C++17之前,所有複製省略情況都獲得允許,但不是必要的。C++17改變了prvalue的語義,使先前屬於暫時物件省略的若干情況改為直接建構。

回傳的prvalue與具名區域變數 #

自C++17起,從函式回傳函式回傳型別的prvalue時,會直接建構結果物件。因此,即使複製建構函式和移動建構函式已被刪除,也不會阻止這種形式;不過,在return陳述式處,回傳型別的解構函式仍必須可存取且未被刪除:

cpp
struct Token {
    Token();
    Token(const Token&) = delete;
    Token(Token&&) = delete;
};

Token make_token() {
    return Token{}; // 自C++17起保證直接建構
}

具名回傳值最佳化(NRVO)仍然是選擇性的,包括C++17及後續版本:

cpp
struct Widget {};

Widget make_named_widget() {
    Widget widget;
    return widget; // 可能套用NRVO;需要可行的複製或移動操作
}

當NRVO不適用時,return陳述式中的符合條件的區域變數會在多載解析中被視為右值。不要僅為了要求這種行為而寫 return std::move(token);。這可能抑制NRVO,並將運算式從符合NRVO條件的名稱改變為xvalue。請直接回傳具名區域變數。

介面與生命週期設計 #

當呼叫端接收獨立結果時,優先回傳已完成的值:

cpp
#include <string>

std::string make_label(int id) {
    return "item-" + std::to_string(id);
}

回傳值不是對區域物件的參照。只有在被參照物件的生命週期長於呼叫,且借用或別名存取是預期契約時,回傳參照才是正確的:

cpp
const Config& active_config(); // 參照生命週期較長的儲存空間

絕不要回傳對自動區域變數的左值參照或右值參照。右值參照不會將區域物件的生命週期延長至return之後;它只傳達參照類別。相反地,將暫時物件繫結至區域的 const T& 或 T&& 會將該暫時物件的生命週期延長至該區域參照的生命週期,但不會延長至函式所回傳參照的生命週期。

撰寫以值回傳的介面時,不要使用防禦性移動;只有在已證實存在成本時才進行測量。C++17的保證適用於規定的prvalue情況;NRVO、基底子物件初始化,以及轉換至不同結果型別仍是獨立情況,各自具有其複製或移動需求。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)