为什么C ++ 11从std :: vector的fill构造函数的原型中删除默认值?

在C ++ 98中, std::vector的fill构造函数的原型具有初始值设定项的默认值。

 explicit vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()); 

C ++ 11使用两个原型。

 explicit vector (size_type n); vector (size_type n, const value_type& val, const allocator_type& alloc = allocator_type()); 

(在C ++ 14中,填充构造函数再次发生了变化,但这不是这个问题的要点。)

参考链接在这里 。

为什么C ++ 11不推荐使用默认的初始值设定项value_type()

顺便说一句,我试着用clang++ -std=c++11来编译下面的代码,它发出了一个错误,这意味着值types仍然需要像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个默认构造来replace它。 另外,它避免了构build原型。

假设你的类看起来像这样:

 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, ov); } bulky& operator=(bulky&& o) { std::swap(v,ov); return *this; } }; 

这是一个总是拥有1000 int s的缓冲区的类。

如果我们再创build一个bulky的vector:

 std::vector<bulky> v(2); 

在C ++ 98中这个分配了3倍1000个整数。 在C ++ 11中,这个分配只有1000倍整数的2倍。

另外,C ++ 98版本要求该types是可复制的。 在C ++ 11中有不可复制的types,如std::unique_ptr<T> ,并且使用C ++ 98签名不能生成缺省构造的唯一指针vector 。 C ++ 11签名没有问题。

 std::vector<std::unique_ptr<int>> v(100); 

如果我们仍然拥有C ++ 98版本,上述方法将不起作用。

构造函数被分成两部分的原因是为了支持“仅移动”types,比如unique_ptr<T>

这个构造函数:

 vector(size_type n, const T& value, const Allocator& = Allocator()); 

要求T是复制可构造的,因为必须从value复制n T来填充vector

这个构造函数:

 explicit vector(size_type n, const Allocator& = Allocator()); 

不要求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%20constructors,%20copy ,%20于是%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); 

原因完全一样。 第一个需要默认的可构造但不可复制的可构造(以支持默认的可构造的仅移动types),第二个需要复制可构造。

这些变化不是100%向后兼容。 对于某些types(例如引用计数智能指针),从默认构造对象复制构造与默认构造不同。 然而,支持移动types的好处被认为是值得这个API破损的成本。