2012-09-02 50 views
2

我想寫的很簡單任何對象,它可以容納任何類型的對象。我希望它在容器內部使用,來實現異構容器。在「異構對象」類中複製構造函數

#include <iostream> 
#include <vector> 
#include <string> 

struct Any 
{ 
    template < typename T > 
    Any(const T & t) 
     :p(new storageImpl<T>(t)) { } 

    ~Any() 
    { 
     delete p; 
    } 

    struct storage 
    { 
     virtual ~storage() {} 
    }; 

    template <typename T> 
    struct storageImpl : storage 
    { 
     storageImpl(const T & t) : data(t) {} 
     T data; 
    }; 

    template <typename T> 
    T & get() 
    { 
     storageImpl<T> * i = static_cast<storageImpl<T>*>(p); 
     return i->data; 
    } 

    storage * p; 
}; 

使用

int main() 
{ 
    //block1 
    Any copy(Any(std::string("foo")));  
    std::cout << copy.get<std::string>(); 

    //block2 
    std::vector<Any> cont; 
    cont.push_back(Any(5)); 
    cont.push_back(Any(37.9f)); 
    std::cout << cont[0].get<int>();  
    std::cout << cont[1].get<float>(); 
} 

我有一份建設問題。

當我將Any推入向量(// block2)時,未命名的Any被破壞,所以指針被刪除,並且推送的對象不再有效。

所以我有2個問題:

1,如何編寫類中的任何拷貝構造函數?

2,爲什麼不是無名Any在BLOCK1破壞,因此它的指針不會被刪除?\

編輯 我曾嘗試

template <typename T> 
Any(const Any & rhs) 
    :p(new storageImpl<T>(rhs.get())) 
{ 
} 

但它不會被觸發。

+1

如果您不知道,已經有[Boost.Any](http://www.boost.org/doc/libs/1_51_0/doc/html/any.html)。 – kennytm

+0

@KennyTM我知道,但我不想使用提升。 – relaxxx

回答

2

Any不是模板類。試圖將複製構造器模板化爲template <typename T> Any(const Any & rhs)是沒有意義的。

你可以做的是使用virtual constructor成語,讓storageImpl自己複製。這也是Boost.Any中使用的方法。

struct Any { 
    template < typename T > 
    Any(const T& t) : p(new storageImpl<T>(t)) {} 

    Any(const Any& other) : p(other.p->clone()) {} 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

    ~Any() { delete p; } 

    struct storage { 
     virtual ~storage() {} 
     virtual storage* clone() = 0; 
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    }; 

    template <typename T> 
    struct storageImpl : storage { 
     storageImpl(const T & t) : data(t) {} 

     virtual storage* clone() { return new storageImpl(data); } 
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

     T data; 
    }; 

    template <typename T> 
    T& get() { 
     storageImpl<T>* i = static_cast<storageImpl<T>*>(p); 
     return i->data; 
    } 

    storage * p; 
}; 

請注意,此實現有很多問題,例如, get()方法將不檢查Any是否真的擁有T.使用經過良好測試的庫例如Boost.Any


爲什麼不無名任何BLOCK1破壞,因此它的指針不會被刪除?

Copy elision

+0

非常感謝Kenny,類型檢查不是一個真正的問題,我打算只用一次,因爲一個小問題,所以我不想使用boost。 – relaxxx

1
  1. 做一個深拷貝,即動態地分配一個新對象storageImpl<T>,初始化爲來自物體的一個的被複制的內容。

  2. 您可以有copy elision發生,這意味着沒有臨時對象被刪除。

或者,使用boost::any避免所有問題。

+0

謝謝,但是如何編寫這樣的構造函數?請參閱編輯我的問題以瞭解我所嘗試的內容。並感謝'複製elision' – relaxxx

+0

@relaxxx你確定代碼編譯器?您在'const'引用上調用非const方法'get()'。其實,看起來你需要知道'rhs'的'T'才能複製。 – juanchopanza