我仍然对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()
使用)的模板魔法需要存在这些构造函数中的任何一个,但实际上从未调用过。但是,如果你没有调用它,为什么还需要一个方法?
答案 0 :(得分:4)
标准的最新修订版(n3376)说:
12 - 如果
size() < sz
, 将sz - size()
默认插入的元素附加到序列中 13 - 要求:T
应为MoveInsertable
,DefaultInsertable
为*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);