在 std::vector::clear 之后对矢量中的构造/破坏感到困惑

Confusion about construction/destruction in vector after std::vector::clear

本文关键字:clear vector std 之后      更新时间:2023-10-16
#include <iostream>
#include <vector>
class A
{
public:
    A() { std::cout << "constructor" << std::endl; }
    ~A() { std::cout << "destructor" << std::endl; }
};
int main()
{
    std::vector<A> myvec;
    myvec.push_back(A());
    myvec.push_back(A());
    myvec.clear();
    return 0;
}

输出:

constructor
destructor
constructor
destructor
destructor
destructor
destructor

此处有五个对析构函数的调用。前两个是由于传递给push_back的临时。还有其他三个电话,但我预计一个两个额外的电话。

myvec.clear()只会清除两个内容,因此A析构函数应该只调用两次(而不是三次(。 为什么调用一个额外的时间析构函数?

但是,如果我只向量push_back一个元素,而不是两个,则输出符合我的预期。

在这种情况下

,对std::vector::clear的调用并不重要,因为当myvec超出范围时,其内容无论如何都会被销毁。


让我们考虑一下

class A
{
public:
    A()  { std::cout << "constructor" << std::endl; }
    ~A() { std::cout << "destructor" << std::endl; }
    A (const A &) { std::cout << "A(A&)n"; }
};
int main()
{
    std::vector<A> myvec;
    std::cout << "Firstn";
    myvec.push_back(A());
    std::cout << "Secondn";
    myvec.push_back(A());
    std::cout << 'n'; // to separate the final destruction
    myvec.clear();
}

哪些输出

First
constructor <-- First A _temporary_ object created when pushing_back
A(A&)       <-- vector makes a *copy* of the temporary
destructor  <-- Temporary A is destroyed
Second     
constructor <-- Second A _temporary_ object created when pushing_back
A(A&)       <-- Reallocation happens: vector can't copy because it ran out of space
A(A&)       <-- Copy of the second temporary
destructor  <-- Destroy of the temporary
destructor  <-- Destroy of the first element
destructor
destructor

如果您std::vector::reserve一些空间,则可以删除重新分配所做的副本

std::vector<A> myvec;
myvec.reserve(8);

这证实了所说的话

First
constructor
A(A&) 
destructor
Second
constructor
A(A&) 
destructor

push_back仍在复制参数:这可以通过使类可移动来进一步优化。

A(A&&) noexcept = default;
A& operator=(A&&) noexcept = default;
First
constructor
destructor
Second
constructor
destructor

很可能是由于在第一个和第二个push_back之间发生的重新分配。如果您提前reserve一些空间,那么正如您所期望的那样,在两个push_back之后,将2释放。

试试这个稍微修改过的程序版本。现在有一个复制构造函数和一个可选的reserve(请参阅程序中的注释(。正在发生的事情会更加清晰。

#include <iostream>
#include <vector>
using namespace std;

class A
{
  public:
  A()            { cout << " constructor" << endl; }
  A(const A & a) { cout << " copy constructor" << endl; }
  ~A()           { cout << " destructor" << endl; }
};

int main()
{
  vector<A> myvec;
  // myvec.reserve(100);                   // <<< remove comment to see the difference
  cout << "pushback 1" << endl;
  myvec.push_back(A());
  cout << "pushback 2"  << endl;
  myvec.push_back(A());
  cout << "pushback 3"  << endl;
  myvec.push_back(A());
  cout << "clear"  << endl;
  myvec.clear();
  cout << "end clear" << endl;
  return 0;
}