太多的复制向量我搞不懂

too many copy ctors i cant figure out

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

class items{
    char * name;
public:
    items(const char * str){
        int len = strlen(str);
        this->name = new char [len];
        strcpy(this->name,str);
        cout << "Default ctor " << this->name << " \t@" << (this) << endl;
    }

    items(const items& obj){
        int len = strlen(obj.name);
        this->name = new char [len];
        strcpy(name,obj.name);
        cout << "Copy ctor " << this->name << " \t@" << this << endl;
    }

    ~items(){
        cout << "dtor \t" << this->name << "\t@" << this << endl;
        delete [] name;
    }

    const char * getName() const{
        return this->name;
    }
};

ostream& operator<<(ostream& stream, const items& obj){
    stream << obj.getName();
    return stream;
}

int main(int argc, char ** argv){
    items Ruler("Ruler"), Pencil("Pencil"), Book("Book"), Notebook("Notebook"), Sharpener("Sharpener");


    vector<items> school;
    school.push_back(Ruler);
    school.push_back(Pencil);
    school.push_back(Book);

    return 0;
}

我有奇怪的结果。你能解释一下幕后发生的事情吗? 结果:

Default ctor Ruler  @0x62ff1c
Default ctor Pencil     @0x62ff18
Default ctor Book   @0x62ff14
Default ctor Notebook   @0x62ff10
Default ctor Sharpener  @0x62ff0c
Copy ctor Ruler     @0x9cd1d0
Copy ctor Pencil    @0x9cd504
Copy ctor Ruler     @0x9cd500
dtor    Ruler   @0x9cd1d0
Copy ctor Book  @0x9c0510
Copy ctor Ruler     @0x9c0508
Copy ctor Pencil    @0x9c050c
dtor    Ruler   @0x9cd500
dtor    Pencil  @0x9cd504
dtor    Ruler   @0x9c0508
dtor    Pencil  @0x9c050c
dtor    Book    @0x9c0510
dtor    Sharpener   @0x62ff0c
dtor    Notebook    @0x62ff10
dtor    Book    @0x62ff14
dtor    Pencil  @0x62ff18
dtor    Ruler   @0x62ff1c

默认构造后发生了什么?为什么这个统治者创造了太多的副本并摧毁了它们?这里有什么问题?

std::vector 管理自己的内存。这意味着 std::vector 仅存储对象的副本,这意味着该对象必须具有有意义的复制构造函数(和赋值运算符,但这是另一个问题)。

当向量的析构函数被调用时,向量持有的内存被释放。 std::vector 在删除对象时也会调用对象的析构函数(通过擦除、pop_back、清除或矢量的析构函数)。

基本上发生的事情是,如果向量已满并且您正在推动一个元素,则向量需要调整大小。因此,当您在向量上按下 Ruler 时,会创建一个大小为 sizeof(items) 的数组,并且会复制数据(第一个复制构造函数调用 Ruler)。然后你将 Pencil 推到向量上(第一个复制构造函数调用 Pencil),但是向量内存不足,因此分配了一个新数组,其大小是先前大小的两倍 2 * sizeof(items)并将旧数组复制到新数组(第二个复制构造函数调用Ruler)并销毁旧数组(第一个析构函数在旧数组中调用Ruler)等等......

您的 "default constructor" 接受一个参数,因此不是 C++ 意义上的默认构造函数:默认构造函数可以在没有任何参数的情况下调用。

关于你的问题,顺序似乎是这样的:

  1. 最初所有对象都被构建。
  2. 有一个 Ruler 对象的副本,将其插入到 school 向量中。
  3. 当插入 Pencil 时,首先复制此对象,但显然 school 向量中没有足够的 space:Pencil 对象被复制到新分配的位置,然后 Ruler 被复制过来,原来的 space 被销毁。
  4. 当插入 Book 时,会发生相同的顺序:Book 被复制到一个新位置,然后 RulerPencil 也被复制到那里。
  5. 最后,所有对象都被销毁了。

从某种意义上说,该序列有些混乱,因为 std::vector 通常不会那样做:它通常会在开始时创建一个可以容纳多个元素的小数组。看起来,所使用的实现从只有一个的 capacity() 开始,然后从那里将容量加倍。您可以通过查看对 school.push_back() 的调用之间的 school.capacity() 来验证此行为:只要 capacity() 增加,底层数组就会增加。

考虑到您正在分配内存,您可能需要考虑一个移动构造函数,它传输存储的内存而不是分配一个新数组来容纳一个副本,然后只 delete 原始数组。移动构造函数看起来像这样:

items::items(items&& other)
    : name(other.name) {
    this->name = nullptr;
}