2

我仍然对std::vector::resize(). 考虑以下代码(另请参阅std::vector<type> 的类型要求

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  A(A const&) { assert(0); }  // is required but doesn't fire in vector::resize
  int X;
};

int main()
{
  std::vector<A> a;
  a.resize(4);        // would not compile without A::A(A const&) or A::A(A&&)
}

如果没有A::A(A const&)or A::A(A&&),则 with 行a.resize(4);无法编译。但是,该构造函数永远不会被调用:assert(0)不会触发!有人可以向我解释一下吗?

我的解释是,allocator_traits<>(used by std::vector::resize()) 的模板魔法要求这些构造函数中的任何一个的存在,但实际上从未调用过。但是,如果您不调用方法,为什么还需要该方法的存在呢?

4

3 回答 3

4

该标准的最新版本(n3376)说:

12 - 如果size() < sz,将默认插入的元素附加sz - size()到序列中。
13 - 要求:TMoveInsertableDefaultInsertable进入*this

The implication is that MoveInsertable is required for any reallocation that might occur, while DefaultInsertable is required for the actual appending. So your copy or move constructor will fire only if your vector already contains elements and needs to be reallocated.

Indeed, if we write:

std::vector<A> a;
a.resize(1);
assert(!a.empty() && a.capacity() < 4);
a.resize(4);

then the copy- or move-constructor of A is called, and your assert is triggered.

于 2012-09-04T08:50:10.680 回答
3

为了resize向量,如果向量没有足够的空间来容纳新大小所需的元素,则必须将现有元素放入新分配的内存块中。这是通过复制构造它们来完成的。所以你必须有一个复制构造函数来调整向量的大小。在这种情况下,没有现有元素,因此不会调用复制构造函数。但它仍然必须存在。

于 2012-09-04T08:48:40.020 回答
0

In your example, when you call vector::resize() method, the constructor is called instead of the copy constructor. That is why you do not see assert being triggered.

As for why you need the copy-constructor (and move constructor, which you haven't defined and declared), is that the template types have to be Copy-constructable and move-constructable. [container.requirements.general]/15 defines the requirements for container's type :

— T is DefaultInsertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p);
— An element of X is default-inserted if it is initialized by evaluation of the expression allocator_traits<A>::construct(m, p);
where p is the address of the uninitialized storage for the element allocated within X.
— T is CopyInsertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p, v);
— T is MoveInsertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p, rv);
— T is EmplaceConstructible into X from args , for zero or more arguments args, means that the following expression is well-formed: allocator_traits<A>::construct(m, p, args);
— T is Erasable from X means that the following expression is well-formed: allocator_traits<A>::destroy(m, p);
于 2012-09-04T08:50:34.300 回答