【问题标题】: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++ vector


【解决方案1】:

容量是否被复制?

实际上,没有。我在Clang and GCCMSVC 在线测试过,都没有复制容量。

最后一行会重新分配吗?

如果容量小于要保留的参数(即它没有被复制),那么是的。

标准对此有任何说明还是保持沉默?

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】:
    1. 正如下面的 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;
        }
    
    1. 正如 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);
          }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      • 2013-03-06
      • 1970-01-01
      • 2021-01-22
      • 1970-01-01
      • 1970-01-01
      • 2014-06-18
      相关资源
      最近更新 更多