2016-09-11 35 views
-1

我想(unsuccesfully)來創建對象的矢量和使用polimophism無需人工內存管理和任何類型的指針(*的unique_ptr,shared_ptr的,weak_ptr的等)依賴raii成語。使用移動語義和引用的矢量抽象類的兒童

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

struct A{ 
    virtual void foo()=0; 
    virtual ~A(){} 
}; 
struct C:A{ 
    int bar; 
    C(int bar):bar(bar){} 
    virtual void foo(){ 
     cout << bar << endl; 
    } 
    virtual ~C(){} 
}; 
struct B:A{ 
    vector<A> &&bar; 
    int f; 
    B(int f, vector<A> bar):f(f),bar(bar){} 
    B(int f, vector<A> &bar):f(f),bar(bar){} 
    B(int f, vector<A> &&bar):f(f), bar(bar){} 
    virtual void foo(){ 
     cout << f << endl; 
     for(auto &f: bar){ 
      f.foo(); 
     } 
    } 
    virtual ~B(){} 
}; 

int main() { 
    B b{1, vector<A>{C{1},C{2}}}; 
    b.foo(); 
    return 0; 
} 

但它不編譯。我做錯了什麼?

回答

2
std::vector<A> something 

是其中用於A動態分配存儲的矢量,並且僅A,添加對象時。

載體的存儲類型是A,它存儲的A實例。

當你把第一個C到它,但它的東西沿着線:

void push_back(const A& a) // NOTE: A, not C, downcasting occurs 
{ 
    // extreme aproximation 
    if (something.begin_ == nullptr) { 
     something.begin_ = new A; 
     something.begin_[0] = a; // A::operator=(const A&); 
     something.capacity_ = something.end_ = something.begin_ + 1; 
    } else { 
     .. 
    } 
} 

因爲C繼承A它能夠垂頭喪氣了這一點。但是,它只會複製傳遞給它的對象的A部分,因爲矢量的存儲類型爲A,因此您的int bar未在C中被複制。

這被稱爲切片,它的唯一方法是動態的(指針或std :: any)或使用聯合的危險路徑。

- 編輯 -

的第二個問題是你期望std::vector<A> &&bar做什麼?它引用的臨時對象到期的構造函數表達式的末尾:

B b{1, vector<A>{C{1},C{2}}}; // temporary vector is destroyed 
// b.bar is dangling rvalue reference 

- 編輯2 -

你的問題標題中包含「使用移動語義」,但在編輯中提到的,你只存儲一個rvalue 參考。移動語義是關於轉移中:考慮這個簡單strdup包裝:除了

struct Strdupper { 
    char* str_; 
    Strdupper() = delete; 
    Strdupper(const char* str) : str_(strdup(str)) {} 
    ~Strdupper() { if (str_) free(str_); } 
    Strdupper(const Strdupper& rhs) { str_ = strdup(rhs.str_); } 
    Strdupper(Strdupper&& rhs) str_(rhs.str_) { rhs.str_ = nullptr; } 
    Strdupper& operator=(const Strdupper& rhs) { if (str_) free(str_); str_ = strdup(rhs.str_); return *this; } 
    Strdupper& operator=(Strdupper&& rhs) { std::swap(str_, rhs.str_); return *this; } 
    // ... 
}; 

右值的參考,你的B類需要實際載體和std::move輸入參數值存儲到其構造函數中調用它的移動構造函數:

class B { 
    std::vector<X> vec_; 

public: 
    B() = default; 
    B(const std::vector<X>& vec) : vec_(vec) {} // copy semantics 
    B(std::vector<X>&& vec) : vec_(std::move(vec)) {} // move semantics 
}; 
+0

你'Strdupper ::運算符=(常量Strdupper&)'泄漏內存。 – aschepler

+0

@aschepler呃,固定。 – kfsone

+0

謝謝你的回答。如果我們得到右值引用,爲什麼我們應該在構造函數中使用std :: move? – KOLANICH