2

C++11 で使用される型の要件についてはまだ混乱していますstd::vectorが、これはバグのあるコンパイラ (gcc 4.7.0) が原因である可能性があります。このコード:

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  int X;
};

int main()
{
  std::vector<A> a;
  a.resize(4);
}

正常に動作し、期待される出力を生成します。これは、(明示的に指定された) デフォルトの ctor が呼び出されたことを示します (暗黙のコピー ctor ではありません)。ただし、削除されたコピー ctor をクラスに追加すると、viz

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  A(A const&) = delete;
  int X;
};

gcc 4.7.0 はコンパイルされませんが、削除された ctor を使用しようとします。それは正しい動作ですか、それともバグですか?前者の場合、コードを機能させる方法は?

4

5 に答える 5

14

CopyInsertable他の人が指摘したように、C++ 11標準は実際に必要です。ただし、これは C++11 標準のバグです。これはその後、N3376MoveInsertableおよびに修正されましたDefaultInsertable

vector<T, A>::resize(n)メンバー関数にはとMoveInsertableが必要DefaultInsertableです。これらは大まかに、アロケータがデフォルトの定義を使用する場合に変換さDefaultConstructibleれます。MoveConstructibleAconstruct

次のプログラムは、clang/libc++ を使用してコンパイルされます。

#include <vector>
#include <iostream>

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  A(A&&) = default;
  int X;
};

int main()
{
  std::vector<A> a;
  a.resize(4);
}

そして私のために印刷します:

 A::A(); this=0x7fcd634000e0
 A::A(); this=0x7fcd634000e4
 A::A(); this=0x7fcd634000e8
 A::A(); this=0x7fcd634000ec

上記の移動コンストラクターを削除して、削除されたコピー コンストラクターに置き換えると、OP の質問で正しく示されているAようにMoveInsertableMoveConstructible削除されたコピー コンストラクターを使用しようとします。

于 2012-09-03T16:59:31.783 に答える
3

C++11 では、要件は実行される操作によって異なります。の場合std::vector<T>::resize()、 の要件は、ベクトル内にTあることです。CopyInsertable

§23.3.6.3 から

void resize(size_type sz);

....

Requires: *thisTに入る必要があります。CopyInsertable

于 2012-09-03T16:36:52.983 に答える
2

ベクトルでクラスを使用するには、コピー コンストラクター/代入演算子または noexcept 移動コンストラクター/代入演算子が必要です。GCC は、これらのいずれも持たない例をコンパイルしないことは非常に正しいです。

ベクトルに含まれるものをコピーまたは移動することができずに、ベクトルを除外して何かを行うにはどうすればよいでしょうか?

最初の例が機能する理由は、コピー コンストラクター、ムーブ コンストラクター、または代入演算子を定義していないため、既定値が取得されるためです。2 番目の例では、コピー コンストラクターを明示的に削除したため、自動生成されたコンストラクターまたは代入演算子は取得されません。

于 2012-09-03T16:34:55.007 に答える
2

ideoneでは、デフォルト コンストラクターへの呼び出しが 1 つあります。しかし、4 つのオブジェクトが作成されており、残りは何らかの方法で構築する必要があります。実際には、プロトタイプ オブジェクトがデフォルトで構築され、その後 4 回コピーされます。

C++11 標準 (セクション 23.3.6.3) は、「初期化された値」オブジェクトが挿入されると述べていますが、型がコピー可能であることも必要とします。

void resize(size_type sz);

  • 効果: の場合sz <= size()、 と同等erase(begin() + sz, end());。の場合、値が初期化された要素をシーケンスsize() < szに追加します。sz - size()
  • 必須:TCopyInsertable入る必要があります*this

ここにはコンパイラのバグはありません。間違っているのはあなたのコードです。

于 2012-09-03T16:35:33.413 に答える
1

void resize(size_type)requires CopyInsertable、つまり、アロケーターが型を構築コピーできる必要があります。

::new((void*)p)A(A());

これは、コピー コンストラクターが必要であることを意味します。カスタム アロケータを使用してこれをバイパスできるはずです。

struct Allocator: public std::allocator<A> {
  void construct(A *, const A &) { }
};

ただし、libstdc++ はこれを尊重しません。Should (in C++11) std::vector::resize(size_type) work for default constructible value_type int[4]? を参照してください

于 2012-09-03T16:37:06.440 に答える