C++ 98では、std::vector
のfillコンストラクタのプロトタイプには、初期化子のデフォルト値があります。
explicit vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
C++ 11は2つのプロトタイプを使用します。
explicit vector (size_type n);
vector (size_type n, const value_type& val,
const allocator_type& alloc = allocator_type());
(C++ 14では、フィルコンストラクターが再び変更されましたが、この質問のポイントではありません。)
参照リンクは here です。
C++ 11がデフォルトの初期化子値value_type()
を非推奨にしたのはなぜですか?
ところで、私はclang++ -std=c++11
を使用して次のコードをコンパイルしようとしましたが、エラーが発生しました。つまり、値型にはS() {}
のようなデフォルトコンストラクタが必要です。
#include <vector>
struct S {
int k;
S(int k) : k(k) {} // intentionally remove the synthesized default constructor
};
int main() {
std::vector<S> s(5); // error: no matching constructor
}
C++ 98はプロトタイプオブジェクトを取得し、それをn回コピーしました。デフォルトでは、プロトタイプはデフォルトで構築されたオブジェクトでした。
C++ 11バージョンは、デフォルトで構築されたn個のオブジェクトを構築します。
これにより、n個のコピーが削除され、n個のデフォルト構造に置き換えられます。さらに、プロトタイプの構築を回避します。
クラスが次のようになっているとします:
struct bulky {
std::vector<int> v;
bulky():v(1000) {} // 1000 ints
bulky(bulky const&)=default;
bulky& operator=(bulky const&)=default;
// in C++11, avoid ever having an empty vector to maintain
// invariants:
bulky(bulky&& o):bulky() {
std::swap(v, o.v);
}
bulky& operator=(bulky&& o) {
std::swap(v,o.v);
return *this;
}
};
これはalwaysが1000
int
sのバッファを所有するクラスです。
次にbulky
のベクトルを作成すると:
std::vector<bulky> v(2);
c ++ 98では、これは1000の整数の3倍を割り当てました。 C++ 11では、これは1000整数の2倍のみを割り当てました。
さらに、C++ 98バージョンでは、型がコピー可能であることが必要です。 C++ 11にはstd::unique_ptr<T>
などのコピー不可の型があり、デフォルトで構築された一意のポインターのvector
はC++ 98署名を使用して生成できません。 C++ 11シグネチャには問題ありません。
std::vector<std::unique_ptr<int>> v(100);
C++ 98バージョンがまだある場合、上記は機能しません。
コンストラクターが2つに分割された理由は、unique_ptr<T>
などの「移動専用」タイプをサポートするためです。
このコンストラクタ:
vector(size_type n, const T& value, const Allocator& = Allocator());
T
を作成するには、n
T
sをvalue
からコピーする必要があるため、vector
をコピー構築可能にする必要があります。
このコンストラクタ:
explicit vector(size_type n, const Allocator& = Allocator());
doesnotは、T
がコピー構築可能であることを要求します。デフォルトのみ構築可能です。
後者のコンストラクタはunique_ptr<T>
で機能します:
std::vector<std::unique_ptr<int>> s(5);
前者のコンストラクタはそうではありません。
この変更を行った提案は次のとおりです。 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1858.html#23.2.4.1%20-%20vector% 20コンストラクタ、%20copy、%20and%20assignment
そして、この論文にはいくつかの理論的根拠がありますが、確かに少し簡潔です: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html
Fwiw、resize
:
void resize(size_type sz, T c = T());
に分割されました:
void resize(size_type sz);
void resize(size_type sz, const T& c);
まったく同じ理由で。 1つ目は、デフォルトの構築可能だがコピー可能な構築物を必要とせず(デフォルトの構築可能な移動専用タイプをサポートするため)、2つ目はコピー構築可能を必要とします。
これらの変更は、100%下位互換性がありませんでした。一部のタイプ(例:参照カウントスマートポインター)では、デフォルトで構築されたオブジェクトからのコピー構築は、デフォルトの構築とは異なります。ただし、移動専用タイプをサポートする利点は、このAPI破損のコストに見合うと判断されました。