[英]C++ lvalues, rvalues, references, parameters, and performance
所以我有一個函數,需要將std :: vector作為參數。 我想知道最佳的聲明參數的方法,這樣底層數組就不會很深,因為它可能很大。
// which should I choose?
void myFunc(std::vector<char>); // 1
void myFunc(std::vector<char>&); // 2
void myFunc(std::vector<char>&&); // 3
void myFunc(std::vector<char>*) // 4
我應該選擇哪一個? 另外,我不會在函數中修改向量,所以我不應該添加const嗎? 我應該重載該功能並結合使用嗎?
無論如何,如果要在函數中復制它:
void myFunc(std::vector<char>);
如果您只想讀取參數而不復制它:
void myFunc(const std::vector<char>&);
如果要修改傳遞給函數的原始向量,請執行以下操作:
void myFunc(std::vector<char>&);
如果你想優化右值, 或者如果你想移動參數到函數:
void myFunc(std::vector<char>&&);
如果您需要能夠表示通過引用傳遞的可選參數:
void myFunc(const std::vector<char>*);
如果需要傳遞非nullptr
要修改的可選參數:
void myFunc(std::vector<char>*);
如果你不想 深拷貝 std::vector
:
將其移入您的函數:
// foo() decalaration void foo(std::vector<int> v); // usage example std::vector<int> v {0, 1, 2, 3}; foo(std::move(v)); // v is moved into foo() and invalid now
您也可以通過相同的方式從函數返回此向量:
// foo() decalaration std::vector<int> foo(std::vector<int> v) { return v.push_back(4), std::move(v); } // usage example std::vector<int> v {0, 1, 2, 3}; v = foo(std::move(v)); // now v is {0, 1, 2, 3, 4} and no one were deep copied
但是請注意,如果您不移動它(調用foo(v)
而不是foo(std::move(v))
),那么它將被深度復制 。 在底層, foo()
參數v
只是由move-constructor構造的 。
通過它作為參考:
// foo() declaration void foo(std::vector<int>& v);
但是現在我們有一個問題:哪些引用和cv限定詞 ? 好吧,一般來說,我們有2種引用類型和4種cv-qualifiers類型,總共有8個聲明:
void foo(std::vector<int>&); void foo(std::vector<int> const&); void foo(std::vector<int> volatile&); void foo(std::vector<int> const volatile&); void foo(std::vector<int>&&); void foo(std::vector<int> const&&); void foo(std::vector<int> volatile&&); void foo(std::vector<int> const volatile&&);
當然,其中的一部分是無用的,應該刪除。 但是盡管如此,太多的聲明也被稱為完美轉發問題 (實際上,當出現問題時就沒有右值引用,因此問題要小2倍)。
例如,如果要修改v
,則至少需要2個功能:
void foo(std::vector<int>&); void foo(std::vector<int>&&);
在這種情況下,您將能夠在左值對象上調用foo()
:
std::vector<int> v; foo(v);
以及臨時的:
foo(std::vector<int>{1, 2, 3, 4, 5});
但是如何只為不同的引用類型和/或cv限定詞編碼一種實現? 讓我介紹通用參考文獻 :
template<typename Vector> void foo(Vector&& v);
Vector&&
始終是引用類型 ,可以推導為
如果將std::vector<int>
類型的左值傳遞給foo()
std::vector<int>&
則為std::vector<int>&
:
std::vector<int> v; foo(v); // v is lvalue
如果您傳遞類型為std::vector<int>
const左值,則為std::vector<int> const&
:
std::vector<int> const v; foo(v); // v is const lvalue
std::vector<int>&&
如果您傳遞右值:
foo(std::vector<int>{0, 1, 2}); // v is rvalue
等等...
但是在這種情況下,您必須檢查Vector
類型的接受程度。 不過那是另一回事了。
而且在這種情況下,我絕對沒有理由傳遞指針而不是引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.