在C ++ 98中,std::vector
的填充构造函数的原型具有初始化程序的默认值。
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中,填充构造函数再次改变,但这不是这个问题的重点。)
参考链接为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
}
答案 0 :(得分:52)
C ++ 98采用原型对象,然后复制了n次。默认情况下,原型是默认构造的对象。
C ++ 11版本构造了n个默认构造的对象。
这消除了n个副本并用n个default-constructions替换它。此外,它避免了构建原型。
假设您的课程如下:
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;
}
};
这是一个总是拥有1000
int
s缓冲区的类。
如果我们然后创建bulky
:
std::vector<bulky> v(2);
在C ++ 98中,这分配了3次1000个整数。在C ++ 11中,这只分配了1000次整数。
此外,C ++ 98版本要求该类型可以复制。 C ++ 11中有不可复制的类型,例如std::unique_ptr<T>
,并且使用C ++ 98签名无法生成vector
默认构造的唯一指针。 C ++ 11签名没有任何问题。
std::vector<std::unique_ptr<int>> v(100);
如果我们仍然使用C ++ 98版本,则上述操作无效。
答案 1 :(得分:47)
构造函数分为两部分的原因是支持“仅移动”类型,例如unique_ptr<T>
。
这个构造函数:
vector(size_type n, const T& value, const Allocator& = Allocator());
要求T
具有可复制性,因为必须从n
复制T
value
以填充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/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);
出于同样的原因。第一个需要默认可构造但不能复制构造(支持默认的可构造移动类型),第二个需要复制可构造。
这些更改并非100%向后兼容。对于某些类型(例如,引用计数的智能指针),从默认构造对象的复制构造与默认构造不同。然而,支持仅移动类型的好处被认为是值得这个API破坏的成本。