简体   繁体   English

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

[英]strange behaviour of std::vector::resize() with gcc 4.7.0

I'm still confused about the behaviour of std::vector::resize() . 我仍然对std::vector::resize()的行为感到困惑。 Consider the following code (see also type requirements for std::vector<type> ) 考虑以下代码(另请参见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&&)
}

Without A::A(A const&) or A::A(A&&) , the line with a.resize(4); 如果没有A::A(A const&)A::A(A&&) ,则带有a.resize(4); doesn't compile. 不编译。 However, that constructor is never called: the assert(0) doesn't fire! 但是,永远不会调用该构造函数: assert(0)不会触发! Can somebody explain that to me? 有人可以向我解释一下吗?

My interpretation is that the presence of either of these constructors is required by the template magic of allocator_traits<> (used by std::vector::resize() ), but is actually never called. 我的解释是,这两个构造函数的存在是allocator_traits<>的模板魔术所必需的(由std::vector::resize() ),但实际上从未调用过。 However, why would you require the presence of a method if you're not calling it? 但是,如果不调用方法,为什么要要求存在该方法?

The latest revision of the standard ( n3376 ) says: 该标准的最新版本( n3376 )说:

12 - If size() < sz , appends sz - size() default-inserted elements to the sequence. 12-如果size() < sz ,则将sz - size()默认插入的元素追加到序列中。
13 - Requires: T shall be MoveInsertable and DefaultInsertable into *this . 13-要求: T必须是MoveInsertableDefaultInsertable*this

The implication is that MoveInsertable is required for any reallocation that might occur, while DefaultInsertable is required for the actual appending. 这意味着可能发生的任何重新分配都需要MoveInsertable ,而实际附加则需要DefaultInsertable So your copy or move constructor will fire only if your vector already contains elements and needs to be reallocated. 因此,仅当向量已经包含元素并且需要重新分配时,您的copy或move构造函数才会触发。

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. 然后调用A的复制或移动构造函数,并触发您的断言。

In order to resize a vector, existing elements must be placed into the newly-allocated chunk of memory if the vector didn't have enough space to hold the elements required by the new size. 为了resize向量的resize ,如果向量没有足够的空间来容纳新大小所需的元素,则必须将现有元素放入新分配的内存块中。 This is done by copy-constructing them. 这是通过复制构造它们来完成的。 So you must have a copy constructor to resize a vector. 因此,您必须具有复制构造函数才能调整向量的大小。 In this case, there are no existing elements, so the copy constructor is not called. 在这种情况下,不存在现有元素,因此不会调用复制构造函数。 But it still must be present. 但是它仍然必须存在。

In your example, when you call vector::resize() method, the constructor is called instead of the copy constructor. 在您的示例中,当您调用vector :: resize()方法时,将调用构造函数,而不是复制构造函数。 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. 至于为什么需要copy-constructor(以及尚未定义和声明的move构造函数)的原因是,模板类型必须是Copy-constructable和move-constructable的。 [container.requirements.general]/15 defines the requirements for container's type : [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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM