开发者

Container that doesn't require its elements to be default and copy constructible

开发者 https://www.devze.com 2023-01-08 14:15 出处:网络
I\'m looking for a C++ container-like class that wraps a typed array of开发者_运维百科 objects that are not necessarily initialized and don\'t have to be default-constructible or copy-constructible. T

I'm looking for a C++ container-like class that wraps a typed array of开发者_运维百科 objects that are not necessarily initialized and don't have to be default-constructible or copy-constructible. This would be interesting for RAII objects that have no well-defined copy semantics. Such a container-like class seems to be fairly easy to write (using an allocator to allocate uninitialized memory and placement new). Is there something like this in Boost that I have just overlooked? I'm not looking for std::vector (which requires its elements to be copy-constructible) or a pointer container, but for something like this:

#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;
}

The solution should work in C++03 (e.g. no move semantics allowed). The question is a bit academical—I'm just wondering why such a class doesn't seem to exist in Boost.


Such a container-like class seems to be fairly easy to write (using an allocator to allocate uninitialized memory and placement new).

And that is exactly what std::vector does. To use placement new, you would have to make a copy.

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

Perhaps boost::ptr_vector would work for non-copyable types (you'd give it pointers).

#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';
    }
}

And in C++0x, containers will accept non-copyable types as long as they are movable (which should normally be implementable for non-copyable types).


In C++0x, the elements of a std::vector don't have to be copy-constructible as long as they're movable.

0

精彩评论

暂无评论...
验证码 换一张
取 消