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

发布于 2024-09-10 23:49:27 字数 3742 浏览 0 评论 0原文

我正在寻找一个类似 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 中似乎不存在。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哽咽笑 2024-09-17 23:49:27

这样一个类似容器的类似乎
相当容易编写(使用
分配器分配未初始化的
内存和布局新)。

这正是 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 中,容器将接受不可复制的类型,只要它们是可移动的(通常对于不可复制的类型应该是可实现的)。

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).

老娘不死你永远是小三 2024-09-17 23:49:27

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文