代码之家  ›  专栏  ›  技术社区  ›  Philipp

不要求其元素是默认的和可复制构造的容器

  •  1
  • Philipp  · 技术社区  · 15 年前

    我正在寻找一个C++类容器类,它封装了一个类型的对象数组,这些数组不一定是初始化的,不必是默认可构造的或可复制的。对于没有定义良好的复制语义的raii对象来说,这是很有趣的。类似容器的类似乎很容易编写(使用分配器分配未初始化的内存并放置新的)。我刚才忽略的助推器中是否有这样的东西?我不是在找 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中工作(例如,不允许移动语义)。这个问题有点学术性,我只是想知道为什么这样的一个班级似乎不存在于升学中。

    2 回复  |  直到 15 年前
        1
  •  4
  •   UncleBens    15 年前

    像这样一个容器的班级似乎 相当容易写(使用 分配程序分配未初始化的 内存和新位置)。

    这正是 std::vector 做。使用放置 new 你得复印一份。

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

    也许boost::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中,容器将接受非可复制类型,只要它们是可移动的(通常对于不可复制类型来说是可实现的)。

        2
  •  1
  •   fredoverflow    15 年前

    在C++0x中,A的元素 std::vector 只要它们是可移动的,就不必是可复制构造的。

    推荐文章