具有不可复制不可移动元素类型的 C++ 容器

2022-01-24 00:00:00 arrays containers c++ noncopyable

我需要一个既不能复制也不能移动的元素容器.这些元素不是默认可构造的,但它们的构造函数得到相同的参数.

I need a container of elements that are neither copyable nor movable. These elements are not default constructible, but their constructors get identical arguments.

容器的大小在其生命周期内不会改变.它应该像内置数组一样简单,但它的大小是在运行时调用构造函数时确定的.

The size of the container does not change during it's lifetime. It should be as simple as a built-in array, but it's size is determined at run-time when the constructor is called.

有没有一种简单的方法来实现它,而无需使用 std::vector> 产生的内存分配和间接开销?

Is there an easy way to implement that without the overhead of memory allocation and indirection incurred by using std::vector<std::unique_ptr<T>>?

推荐答案

这是一个简单但不完整的解决方案,假设每个元素都是用相同的参数构造的.它使用 placement new 就地构造元素(参见还有这个问题):

Here's a simple, yet incomplete solution under the assumption that each element is constructed with the same arguments. It uses placement new to construct the elements in-place (see also this SO question):

#include <cstdlib>
#include <utility>
#include <new>

// sample structure, non-copyable, non-moveable, non-default-constructible
struct Foo
{
  Foo() = delete;
  Foo(const Foo&) = delete;
  Foo& operator = (const Foo&) = delete;
  Foo(Foo&&) = delete;
  Foo& operator = (Foo&&) = delete;

  Foo(int a, char b, double c) : m_a(a), m_b(b), m_c(c) { }

  int m_a;
  char m_b;
  double m_c;
};

template <typename T>
struct MyArray
{
  // Array ctor constructs all elements in-place using the
  // provided parameters
  template <typename... Args>
  MyArray(std::size_t sz, Args&&... args)
    : m_sz(sz),
      m_data(static_cast<T*>(malloc(sz * sizeof(T))))
  {
    for (std::size_t i=0; i<m_sz; ++i)
    {
      new (&m_data[i]) T(std::forward<Args>(args)...);
    }
  }

  ~MyArray()
  {
    for (std::size_t i=0; i<m_sz; ++i)
    {
      m_data[i].~T();
    }
    free(m_data);
  }

  std::size_t m_sz;
  T *m_data;
};

int main()
{
  Foo foo(1, '2', 3.0);
  std::size_t s = 5;
  MyArray<Foo> foo_arr(s, 1, '2', 3.0);
}

请注意,缺少一些内容:

Note that a few things are missing:

  • 如果在 MyArray 的构造函数中抛出异常,此基本实现将泄漏内存.
  • 您可能需要一个迭代器实现、begin()/end() 运算符等,以获得更多便利并获得与标准提供的相同行为容器.
  • 为了说明起见,我也没有考虑适当的封装.您可能应该将 m_szm_data 设为私有成员.
  • This basic implementation will leak memory if an exception is thrown inside MyArray's constructor.
  • You will probably want an iterator implementation, begin()/end() operators etc., for more convenience and to get the same behaviour as provided by the standard containers.
  • For illustration's sake I also didn't bother with proper encapsulation. You should probably make m_sz and m_data private members.

相关文章