2010-07-25 45 views
1

我正在尋找一個C++容器類的類包裝對象的類型化數組,不一定是初始化的,並且不必是默認構造的或可複製構造。對於沒有明確定義的複製語義的RAII對象來說,這會很有趣。這樣一個類似容器的類似乎很容易編寫(使用分配器來分配未初始化的內存和放置新的)。我剛剛忽略了Boost中是否有這樣的內容?我不是在尋找std::vector(這要求它的元素是拷貝構造)或指針容器,但這樣的事情:不需要其元素的容器默認和複製可構造

#include <cstddef> 
#include <memory> 
#include <vector> 
#include <algorithm> 
#include <iostream> 


template< typename T, typename Alloc = std::allocator<T> > 
class FixedVector { 
public: 
    typedef typename Alloc::value_type value_type; 
    typedef typename Alloc::pointer pointer; 
    typedef typename Alloc::reference reference; 
    typedef typename Alloc::const_pointer const_pointer; 
    typedef typename Alloc::const_reference const_reference; 
    typedef typename Alloc::size_type size_type; 
    typedef typename Alloc::difference_type difference_type; 
    typedef pointer iterator; 
    typedef const_pointer const_iterator; 

    explicit FixedVector(size_type size, const Alloc& allocator = Alloc()): 
    m_alloc(allocator), 
    m_size(size), 
    m_data(m_alloc.allocate(size)), 
    m_constructed(size) { } 

    FixedVector(const FixedVector& other): 
    m_alloc(other.m_alloc), 
    m_size(other.m_size), 
    m_data(m_alloc.allocate(m_size)), 
    m_constructed(other.m_constructed) { 
    for (size_type i = 0; i != m_size; ++i) { 
     if (m_constructed[i]) m_alloc.construct(m_alloc.address(m_data[i]), other[i]); 
    } 
    } 

    ~FixedVector() { 
    for (size_type i = 0; i != m_size; ++i) { 
     if (m_constructed[i]) m_alloc.destroy(m_alloc.address(m_data[i])); 
    } 
    m_alloc.deallocate(m_data, m_size); 
    } 

    FixedVector& operator=(FixedVector other) { 
    other.swap(*this); 
    return *this; 
    } 

    // operator[] and other unimportant stuff 

    void swap(FixedVector& other) { 
    std::swap(m_alloc, other.m_alloc); 
    std::swap(m_size, other.m_size); 
    std::swap(m_data, other.m_data); 
    std::swap(m_constructed, other.m_constructed); 
    } 

    void construct(size_type index) { 
    new (m_alloc.address(m_data[index])) T(); 
    m_constructed[index] = true; 
    } 

    template<typename U> 
    void construct(size_type index, U& val) { 
    new (m_alloc.address(m_data[index])) T(val); 
    m_constructed[index] = true; 
    } 

    template<typename U> 
    void construct(size_type index, const U& val) { 
    new (m_alloc.address(m_data[index])) T(val); 
    m_constructed[index] = true; 
    } 

private: 
    Alloc m_alloc; 
    size_type m_size; 
    pointer m_data; 
    std::vector<bool> m_constructed; 
}; 


template<typename T, typename Alloc> 
void swap(FixedVector<T, Alloc>& first, FixedVector<T, Alloc>& second) { 
    first.swap(second); 
} 


namespace std { 
    template<typename T, typename Alloc> 
    void swap(FixedVector<T, Alloc>& first, FixedVector<T, Alloc>& second) { 
    first.swap(second); 
    } 
} 


class Test { 
public: 
    explicit Test(int val): m_val(val) { 
    std::cout << "Test::Test(" << val << ')' << std::endl; 
    } 

    ~Test() { 
    std::cout << "Test::~Test() [with m_val = " << m_val << ']' << std::endl; 
    } 

    int val() const { 
    return m_val; 
    } 

private: 
    int m_val; 

    Test(const Test&); 
    Test& operator=(const Test&); 
}; 

template<typename Char, typename Traits> 
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const Test& object) { 
    return stream << object.val(); 
} 


int main() { 
    typedef FixedVector<Test> FVT; 
    FVT w(10); 
    w.construct(7, 7); 
    w.construct(2, 2); 
    std::cout << "w[2] = " << w[2] << std::endl; 
} 

解決辦法應該工作在C++ 03(例如,沒有移動語義允許)。這個問題有點學術性 - 我只是想知道爲什麼這樣一個類似乎不存在於Boost中。

+0

請注意,您有一個非常奇怪的'operator ='那裏。 – UncleBens 2010-07-25 13:40:59

+0

@UncleBens:爲什麼? – Philipp 2010-07-25 14:26:00

+0

對不起,沒有注意到這個參數是按值傳遞的。 (作業仍然與手邊的問題無關:當存儲類型不可複製時,您無法分配/複製FixedVector。) – UncleBens 2010-07-25 14:40:34

回答

4

這樣的容器狀的類似乎 是相當容易寫(使用 分配器來分配未初始化 存儲器和放置新)。

而這正是std::vector所做的。要使用展示位置new,您必須進行復制。

void store(const T& value) 
{ 
    new (storage) T(value); //<-- invokes copy constructor 
} 

也許提高:: ptr_vector會爲不可複製的工種(你想給它的指針)。

#include <boost/noncopyable.hpp> 
#include <boost/ptr_container/ptr_vector.hpp> 
#include <iostream> 

struct X: boost::noncopyable 
{ 
    X(int x): x(x) {} 
    int x; 
}; 

int main() 
{ 
    boost::ptr_vector<X> vec; 
    for (int i = 1; i < 10; ++i) { 
     vec.push_back(new X(i)); 
    } 

    for (size_t i = 0; i != vec.size(); ++i) { 
     std::cout << vec[i].x << '\n'; 
    } 
} 

和C++ 0x中,容器將只要它們是可移動的(通常應是可執行對於不可複製型)接受不可複製類型。

+0

放置新內容並不意味着可複製性。我建議的班級模板使用新的佈局,並且不要求類型是可複製的。 – Philipp 2010-07-25 13:26:50

+0

@Philipp:好的,沒錯。你的意思是容器將根據給定的參數構造一個對象。那麼你會遇到轉發任意數量參數的問題。再一次,C++ 0x將照顧。 – UncleBens 2010-07-25 13:32:52

+0

是的,我知道轉發問題(這就是爲什麼我只在我的例子中有空和一元構造函數),但有很多Boost庫,其中大量參數列表是手動編寫或使用預處理器或模板自動生成的(如Boost.Tuple),所以我不認爲這是一個普遍問題。重載最多兩個參數已經相當有用。 – Philipp 2010-07-25 13:40:09

1

在C++ 0x中,只要它們是可移動的,std::vector的元素不必是可複製構造的。

+0

謝謝,但是Boost中還有一個不需要C++ 0x的解決方案嗎? – Philipp 2010-07-25 13:27:32

相關問題