7

コピーも移動もできない要素のコンテナが必要です。これらの要素はデフォルトで構築可能ではありませんが、それらのコンストラクタは同一の引数を取得します。

コンテナーのサイズは、その存続期間中は変更されません。組み込みの配列と同じくらい単純である必要がありますが、そのサイズはコンストラクターが呼び出される実行時に決定されます。

を使用することによって発生するメモリ割り当てと間接化のオーバーヘッドなしでそれを実装する簡単な方法はありstd::vector<std::unique_ptr<T>>ますか?

4

4 に答える 4

3

以下は、各要素が同じ引数で構築されているという仮定の下での単純ではあるが不完全な解決策です。配置を使用して要素をインプレースで構築します (newこの SO の質問も参照してください)。

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

いくつか不足していることに注意してください。

  • MyArrayこの基本的な実装では、のコンストラクター内で例外がスローされると、メモリ リークが発生します。
  • 利便性を高め、標準コンテナが提供するのと同じ動作を得るために、おそらくイテレータの実装やbegin()/演算子などが必要になるでしょう。end()
  • 説明のために、適切なカプセル化も気にしませんでした。おそらくプライベートメンバーを作成する必要がm_szあります。m_data
于 2016-09-29T13:17:46.930 に答える
0

管理する要素は移動もコピーもできないため、コンテナーには要素へのポインターのみを含めることができます。std::unique_ptr詳細または要件を知らなければ、生のポインターまたはどちらがより適切かを推測するのは困難です。

固定サイズのコンテナーの場合は、 astd::arrayが適切です。残念ながら、サイズはコンパイル時の式でなければなりません。

別の方法は、生の配列を使用し、placement new を使用して要素を所定の位置に構築することです。ベクトルはプレーン配列のように連続したメモリを使用するため、生の配列の代わりにベクトルを使用することもできますが、それを使用して、コピー不可、移動不可、およびデフォルトで構築不可能なオブジェクトを格納する方法を想像できません。

ところで、C++ でコンパイル時にサイズが不明な、デフォルトではない構築可能なオブジェクトに配列を構築することは、それほど簡単なことではありません。私が見つけた唯一の方法は、適切なサイズの char 配列を構築し、配列の先頭を指すクラスへのポインターを宣言し、新しい配置で要素を構築することです。

char buf = new char[n * sizeof(X)];
X* x = reinterpret_cast<X*>(buf);
for(int i=-1; i<n i++) {
    new (x + i) X(i);  // or whatever appropriate ctor...
}
于 2016-09-29T13:20:33.380 に答える
-1

「std::vector> を使用することによって発生するメモリ割り当てと間接化のオーバーヘッドなしで実装する簡単な方法はありますか?」

オーバーヘッドはごくわずかですが、なぜ気にするのでしょうか? これはほぼ間違いなく時期尚早の最適化であり、メンテナンスの頭痛の種になるだけです。

于 2016-09-29T15:23:47.060 に答える