太多的复制向量我搞不懂
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++ 意义上的默认构造函数:默认构造函数可以在没有任何参数的情况下调用。
关于你的问题,顺序似乎是这样的:
- 最初所有对象都被构建。
- 有一个
Ruler
对象的副本,将其插入到 school
向量中。
- 当插入
Pencil
时,首先复制此对象,但显然 school
向量中没有足够的 space:Pencil
对象被复制到新分配的位置,然后 Ruler
被复制过来,原来的 space 被销毁。
- 当插入
Book
时,会发生相同的顺序:Book
被复制到一个新位置,然后 Ruler
和 Pencil
也被复制到那里。
- 最后,所有对象都被销毁了。
从某种意义上说,该序列有些混乱,因为 std::vector
通常不会那样做:它通常会在开始时创建一个可以容纳多个元素的小数组。看起来,所使用的实现从只有一个的 capacity()
开始,然后从那里将容量加倍。您可以通过查看对 school.push_back()
的调用之间的 school.capacity()
来验证此行为:只要 capacity()
增加,底层数组就会增加。
考虑到您正在分配内存,您可能需要考虑一个移动构造函数,它传输存储的内存而不是分配一个新数组来容纳一个副本,然后只 delete
原始数组。移动构造函数看起来像这样:
items::items(items&& other)
: name(other.name) {
this->name = nullptr;
}
#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++ 意义上的默认构造函数:默认构造函数可以在没有任何参数的情况下调用。
关于你的问题,顺序似乎是这样的:
- 最初所有对象都被构建。
- 有一个
Ruler
对象的副本,将其插入到school
向量中。 - 当插入
Pencil
时,首先复制此对象,但显然school
向量中没有足够的 space:Pencil
对象被复制到新分配的位置,然后Ruler
被复制过来,原来的 space 被销毁。 - 当插入
Book
时,会发生相同的顺序:Book
被复制到一个新位置,然后Ruler
和Pencil
也被复制到那里。 - 最后,所有对象都被销毁了。
从某种意义上说,该序列有些混乱,因为 std::vector
通常不会那样做:它通常会在开始时创建一个可以容纳多个元素的小数组。看起来,所使用的实现从只有一个的 capacity()
开始,然后从那里将容量加倍。您可以通过查看对 school.push_back()
的调用之间的 school.capacity()
来验证此行为:只要 capacity()
增加,底层数组就会增加。
考虑到您正在分配内存,您可能需要考虑一个移动构造函数,它传输存储的内存而不是分配一个新数组来容纳一个副本,然后只 delete
原始数组。移动构造函数看起来像这样:
items::items(items&& other)
: name(other.name) {
this->name = nullptr;
}