移动std :: vector时是否需要保留容量?

Nic*_*las 18 c++ stdvector language-lawyer move-semantics c++11

请考虑以下代码:

std::vector vec;
vec.reserve(500);
size_t cap = vec.capacity();

std::vector newVec = std::move(vec);
assert(cap == newVec.capacity());
Run Code Online (Sandbox Code Playgroud)

在几乎任何你遇到的实现中,这都可行.我不关心实现什么.我想知道标准需要什么.移动的vector容量是否与原始容量相同?或者断言触发器?

Pet*_*der 11

看看标准,似乎移动构造函数不需要任何东西,但是正如@amaurea所说,如果移动构造函数试图分配或释放内存,它将完全打败移动语义的目的,所以我希望能力在所有实现中保持不变.


23.2.1一般容器要求

表达

X u(a);
X u = a;
Run Code Online (Sandbox Code Playgroud)

断言/说明前/后条件

要求:TCopyInsertable是否为X(见下文).
职位:u == a


标准只要求newVec == vec.由于不考虑容量std::vector::operator==,newVec不一定需要具有相同的容量vec.

  • 你的答案的第一段与你在最后一段中的警告相矛盾,因此很难说出你所做的更强烈的断言. (2认同)

Ros*_*ost 9

移动构造函数的C++ 11标准要求std::vector是(表99 - 可识别分配器的容器要求):

X(rv)
X u(rv)
Run Code Online (Sandbox Code Playgroud)
  • 移动构造分配器不得通过异常退出
  • 邮寄:你应该具有与rv此建筑之前相同的元素; 值get_allocator()应与rv.get_allocator()此结构前的值相同.
  • 复杂性:不变

这里没有要求/保证容量.但我们可以得出结论,不变的复杂性隐含地否认任何重新分配.除了重新分配之外,我看不到任何其他合理的理由来改变容量.所以它应该是一样的.

从另一个角度来看,如果移动的向量是空的,那么忽略它并默认构造自身是完全合法的.这仍然是O(1),因为它不需要任何每元素结构.(感谢Nicol Bolas的这个问题).

也可以使用函数hint参数实现将容量缩小到大小std::allocator::allocate:

pointer allocate(size_type, allocator<void>::const_pointer hint = 0);
Run Code Online (Sandbox Code Playgroud)

使用hint未指定,但如果实施需要,则旨在帮助当地.所以一些软化的解决方案可能会传递矢量存储指针,hint并使用realloc它来缩小容量.

结论:看起来标准不保证移动时的容量保留std::vector,存储可能会缩小.

  • "*但我们可以得出结论,不变的复杂性隐含地否认任何重新分配.*"+ 1 (5认同)
  • 看起来像一个实现可能只是减少容量的大小,仍然满足所有的法律要求,虽然这将是一个毫无意义的浪费. (3认同)
  • @Rost:这里的问题是,因为`vec`是空的,所以`newVec`只是忽略空的移动对象和默认构造本身是完全合法的.这仍然是O(1),因为它不需要任何每元素结构. (3认同)
  • @aschepler:但是`std :: allocator <>`接口的哪一部分可以在封面下使用`realloc`? (2认同)
  • @Peter Alexander Ooh,终于我明白了.可是等等!在堆栈上分配和通过`:: operator new(size_t)`分配不是相同的可观察行为! (2认同)