Чтобы понять, что происходит, вам не хватает одного метода в A:
A(const A&) { std::cout << __FUNCTION__ << "(const A&)\n"; }
Тогда вы видите вывод:
A()
A(const A&)
A(const A&)
A(const A&)
~A
~A
~A
~A
Что происходит, так это то, что для каждого push_back вектор выделяет новый непрерывный массив, копирует старое содержимое и уничтожает его. Если считать, первый конструктор копирования предназначен для первого push_back, второй и третий для следующего push_back. Первый деструктор предназначен для второго push_back, два следующих для уничтожения вектора, последний для уничтожения переменной a.
И, между прочим, это полностью определяется реализацией, поскольку его можно распределять по чанкам, что предотвратит немало копий / уничтожений. Вы можете сделать это самостоятельно, используя vector::reserve(size_type n)
.