容量是不是复制到向量中?

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 表示包含Tab 表示 X 类型的值,u 表示标识符,r 表示 X 类型的非常量值,rv 表示非常量右值 输入X

X u(a)

X u = a;

要求: TCopyInsertableX(见下文)。

发帖: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); 

【讨论】:

这只是交换 which reserve 调用将导致重新分配。 swap 对分配器不做任何事情,只交换对象的状态。 那么你可以交换具有不同分配器的向量吗?如果是这样,它不能只交换分配的内存块。 @JDługosz 两个分配器类型不同的向量是不同的向量类型,所以不能交换它们。 @AnatolyS 这在 C++11 中是不正确的。在需要无状态的 C++03 分配器中,因此“swap 对分配器不做任何事情”的说法在某种程度上是正确的。在 C++11 中,swap 对分配器的行为由 allocator_traits&lt;Alloc&gt;::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);
      

【讨论】:

以上是关于容量是不是复制到向量中?的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符复制到字符串向量中

减少 stl 向量的容量

将项目从一个向量复制到另一个向量

C++ 将对象向量中的元素复制到具有此元素的向量中

将轮廓点向量复制到垫子中

如何在 C++ 中将一个对象从一个向量复制到另一个向量?