容量是不是复制到向量中?
Posted
技术标签:
【中文标题】容量是不是复制到向量中?【英文标题】:Is capacity copied in a vector?容量是否复制到向量中? 【发布时间】:2016-06-05 07:12:39 【问题描述】:取以下代码:
std::vector<int> a;
a.reserve(65536);
std::vector<int> b(a); //NOTE: b is constructed from a
a.reserve(65536); // no reallocation
b.reserve(65536);
容量是否被复制?最后一行会重新分配吗?标准对此有任何说明还是保持沉默?
【问题讨论】:
在向量 c-tors 文档中,声明它复制元素。 en.cppreference.com/w/cpp/container/vector/vector std::vector capacity after copying的可能重复 【参考方案1】:容量是否被复制?
实际上,没有。我在Clang and GCC 和MSVC 在线测试过,都没有复制容量。
最后一行会重新分配吗?
如果容量小于要保留的参数(即它没有被复制),那么是的。
标准对此有任何说明还是保持沉默?
vector.cons 中没有提供复制构造函数的定义。相反,我们必须查看container.requirements
X
表示包含T
、a
和b
表示X
类型的值,u
表示标识符,r
表示X
类型的非常量值,rv
表示非常量右值 输入X
。
X u(a)
X u = a;
要求:
T
是CopyInsertable
到X
(见下文)。发帖:
u == a
现在两个容器相等是什么意思?
a == b
==
是等价关系。equal(a.begin(), a.end(), b.begin(), b.end())
换句话说,因为它不需要capacity
在比较中相等,所以没有理由复制capacity
。
【讨论】:
@P0W 没有简单的方法可以链接到 rextester 上的直接代码示例。【参考方案2】:当您调用复制构造函数时,标准没有提及保留容量。所以你对此没有任何保证。
但如果您只需要在副本中保留容量,您可以执行以下技巧,即交换 a 和 b 的状态:
std::vector<int> a;
a.reserve(65536);
std::vector<int> b(a);
b.swap(a); // now b has a's state
assert(b.capacity() == 65536);
【讨论】:
这只是交换 whichreserve
调用将导致重新分配。
swap 对分配器不做任何事情,只交换对象的状态。
那么你可以交换具有不同分配器的向量吗?如果是这样,它不能只交换分配的内存块。
@JDługosz 两个分配器类型不同的向量是不同的向量类型,所以不能交换它们。
@AnatolyS 这在 C++11 中是不正确的。在需要无状态的 C++03 分配器中,因此“swap 对分配器不做任何事情”的说法在某种程度上是正确的。在 C++11 中,swap
对分配器的行为由 allocator_traits<Alloc>::propagate_on_container_swap
自定义。【参考方案3】:
不,vector
复制构造不能保证容量。
你可以这样做:
vector<int> b;
b.reserve( a.capacity() );
b = a;
更好地封装在函数中。
【讨论】:
【参考方案4】:好吧,像下面这样的简单检查表明容量没有被复制:
std::vector<int> a;
a.reserve(65536);
cout << "a.capacity is " << a.capacity() << endl; // prints 65536
std::vector<int> b(a); //NOTE: b is constructed from a
cout << "b.capacity is " << b.capacity() << endl; // prints 0
我相信在将向量a
复制到b
时,b
的容量在大多数编译器中设置为a
的大小;虽然这不能保证。
【讨论】:
这表明您的特定实现不会复制容量。它不会告诉你这是否是一个错误。【参考方案5】:-
正如下面的 SGI STL 矢量源代码所示,operator= 将为恰好 n 个元素保留空间,即 _M_end_of_storage = _M_start + __xlen; .
template <class _Tp, class _Alloc>
vector<_Tp,_Alloc>&
vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x)
if (&__x != this)
const size_type __xlen = __x.size();
if (__xlen > capacity())
iterator __tmp = _M_allocate_and_copy(__xlen, __x.begin(), __x.end());
destroy(_M_start, _M_finish);
_M_deallocate(_M_start, _M_end_of_storage - _M_start);
_M_start = __tmp;
_M_end_of_storage = _M_start + __xlen;
else if (size() >= __xlen)
iterator __i = copy(__x.begin(), __x.end(), begin());
destroy(__i, _M_finish);
else
copy(__x.begin(), __x.begin() + size(), _M_start);
uninitialized_copy(__x.begin() + size(), __x.end(), _M_finish);
_M_finish = _M_start + __xlen;
return *this;
-
正如 SGI STL 向量源代码如下所示,vector 的 复制构造函数 将为 n 个元素保留空间,即 _M_end_of_storage = _M_start + __n;.
template <class _InputIterator>
vector(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type()) : _Base(__a)
typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_initialize_aux(__first, __last, _Integral());
template <class _Integer>
void _M_initialize_aux(_Integer __n, _Integer __value, __true_type)
_M_start = _M_allocate(__n);
_M_end_of_storage = _M_start + __n;
_M_finish = uninitialized_fill_n(_M_start, __n, __value);
【讨论】:
以上是关于容量是不是复制到向量中?的主要内容,如果未能解决你的问题,请参考以下文章