2015-11-05 69 views
4

請原諒我對此主題的不清晰。我正在嘗試創建將大類插入向量的函數。在這個例子中,我使用ints作爲大類。命名右參考

#include <vector> 
#include <iostream> 
using namespace std; 

vector<vector<int>> vectorOfVectors; 

void fn(const vector<int> &v) { 
    vectorOfVectors.push_back(v); 

} 
void fn(vector<int> &&v) { 
    vectorOfVectors.push_back(std::move(v)); 
} 

int main() { 
    vector<int> a({1}); 
    const vector<int> b({2}); 
    fn(std::move(a)); 
    fn(b); 
    cout<<b[0]; 
} 

顯然,我希望在可能的情況下不要複製。我的問題:

  1. 此代碼是否正確?
  2. 有沒有更好的方法來做到這一點?
  3. 對於使用自定義類的相同方法,是否需要定義移動構造函數?

回答

7

此代碼是否正確?

是。出於這個原因,C++ 11增加了std::vector::push_back(T&&)

有沒有更好的方法來做到這一點?

fn(const vector<int> &v)fn(vector<int> &&v)都做同樣的事情,推說法v到的vectorOfVectors結束。代替您的兩個fn函數,您可以使用一個使用完美轉發的函數模板。

template<typename T> 
void fn(T &&v) { 
    vectorOfVectors.push_back(std::forward<T>(v)); 
} 

該如何工作是得益於C++ 11 reference collapsing rulesstd::forward。在v是左值的情況下,模板類型T變爲vector<int>&,但在v是右值的情況下,vector<int>&&。參考摺疊規則意味着vector<int>& &&變爲vector<int>&,而vector<int>&& &&變成vector<int>&&。這正是你想要的,調用版本push_back在左值的情況下做了副本,但是在右值情況下做了移動的版本。

一個缺點是,這有時會導致有趣的診斷,當你弄錯了。 (這裏的「有趣的」意味着來自g ++或clang ++的數百行不可思議的診斷文本)。另一個缺點是模板可能導致「轉換器瘋狂」的情況。

對於使用自定義類的相同方法,是否需要定義移動構造函數?

不一定。如果類未聲明用戶定義的析構函數,複製構造函數,複製賦值運算符或移動賦值運算符,則會得到隱式聲明的移動構造函數。如果類具有不可移動的數據成員或從不能移動或刪除的類派生,則隱式聲明的移動構造函數將被定義爲刪除。

對我來說,這有點太難記。我不知道這是一種好的做法還是壞的做法,但我已經開始使用Foo(const Foo&)=default,對於五個函數的其他規則也有類似的聲明。在很多情況下,我還會將構造函數限定爲explicit以避免「轉換器瘋狂」問題。

+0

可否請您詳細說明「有些情況下是」部分?以及模板如何工作? – SPMP

+0

@ user2308211 - 我將「在某些情況下,是」更改爲您的特定情況。推廣一下,如果你有一個'f(T&)'和'f(T &&)'除了一個'std :: move'或兩個除了'std :: move'之外都是相同的複製粘貼,你應該考慮對一個函數進行templatizing在移動版本的f()中。 –

+2

「模板類型'T'在'v'是一個右值'的情況下成爲'vector &&' - 否,在這種情況下'T'只是'vector '。轉發參考版本還捕捉太陽下的所有東西(重要的是如果你有重載或需要檢查'f(something)'是否格式良好)。最後,如果所討論的類型移動起來很便宜(比如'vector '),一個更簡單的方法是通過值取參數,然後無條件地移動:void f(vectorOfOfVectors.push_back(std ::移動(v)); }'。 –

2
  1. 它確實避免了複製a
  2. 是的。使用push_back意味着您不得不構建至少兩個對象,而emplace_back和完美轉發可以減少工作量。

    template<typename... Ts> 
    auto fn(Ts &&...ts) 
        -> decltype(vectorOfVectors.emplace_back(std::forward<Ts>(ts)...), void()) 
    { 
        vectorOfVectors.emplace_back(std::forward<Ts>(ts)...); 
    } 
    

    http://melpon.org/wandbox/permlink/sT65g3sDxHI0ZZhZ

3.只要你使用push_back,你需要的類,以避免拷貝被移動構造的。如果可以獲取默認定義,則不一定需要自己定義移動構造函數。