Я все еще смущен поведением std::vector::resize()
, Рассмотрим следующий код (см. Также требования к типу для std :: vector<тип>)
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()
), но на самом деле никогда не называется. Однако зачем вам нужен метод, если вы его не вызываете?
Последняя редакция стандарта (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
называется, и ваш утверждается срабатывает.
Чтобы resize
вектор, существующие элементы должны быть помещены во вновь выделенный фрагмент памяти, если в векторе не было достаточно места для хранения элементов, требуемых новым размером. Это делается путем их копирования. Таким образом, вы должны иметь конструктор копирования для изменения размера вектора. В этом случае нет существующих элементов, поэтому конструктор копирования не вызывается. Но это все еще должно присутствовать.
В вашем примере, когда вы вызываете метод 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);