std :: vector :: resize()与gcc 4.7.0的奇怪行为

时间:2012-09-04 08:41:25

标签: c++ constructor c++11 allocation stdvector

我仍然对std::vector::resize()的行为感到困惑。请考虑以下代码(另请参阅type requirements for 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&)A::A(A&&),则a.resize(4);行不会编译。但是,永远不会调用该构造函数:assert(0)不会触发!有人可以向我解释一下吗?

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

3 个答案:

答案 0 :(得分:4)

标准的最新修订版(n3376)说:

  

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

这意味着任何可能发生的重新分配都需要MoveInsertable,而实际附加需要DefaultInsertable。因此,只有当您的向量已经包含元素并且需要重新分配时,您的复制或移动构造函数才会触发。

确实,如果我们写:

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

然后调用A的copy-或move-构造函数,并触发你的断言。

答案 1 :(得分:3)

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

答案 2 :(得分:0)

在您的示例中,当您调用vector :: resize()方法时,将调用构造函数而不是复制构造函数。这就是为什么你没有看到断言被触发的原因。

至于为什么需要复制构造函数(以及尚未定义和声明的移动构造函数),模板类型必须是可复制构造和可移动构造的。 [container.requirements.general] / 15定义了容器类型的要求:

— 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);