string vector
改成上图才能正确识别
、
改成上图才能正确识别
拷贝构造 现代写法
下图左传统 下图右现代
this 指向当前正在构造 / 操作的对象实例。
成员变量也如左图一样
this 指向的对象,调用对应类的成员函数并传入参数
利用string tmp(s.str)会调用接收char*类型的构造函数(字符指针构造,不是默认构)得到tmp(帮我们完成原来我们手动需要完成的数据处理),
上图this是s2的。调用方s1,是传入函数的参数s;
代码进行了交换,如果内置类型没有初始化是随机值,交换给tmp会有问题。因为tmp出了作用域后会析构,释放随机野指针 → 程序崩溃。所以这里将成员变量初始化。tmp销毁空指针
编译器在编译阶段,就计算好了这个类单个实例的总占用字节。在创建(使用构造函数)该类的对象之前,不管是栈、堆、全局区,都必须已经分配好完整的单个实例的总占用字节,这是对象的存储载体。
free,delete,delete[]空时直接返回,不会报错
赋值= 现代写法
调用接收char*类型的构造函数和拷贝构造都行
拷贝构造参数必须是引用。如果是传值传参(不是引用),那么会调用拷贝构造,拷贝构造又会调用传值传参,无穷递归。
赋值参数不用必须是引用,是传值传参,那么会调用拷贝构造,正好将s3拷贝构造给tmp,然后直接交换即可
s1原本的空间就需要释放,交还给tmp,tmp出了作用域后会自动调用析构函数
swap
自己手动模拟 库里模板
以交换两个自定义对象为例:
直接套库里模板会有三次深拷贝,伴随开空间拷贝数据析构等,代价太大。交换内置类型或无深拷贝对象就行
自己手动模拟的也是套库里模板,只不过交换的类型都是内置类型,效率明显提升
库里还有一个全局swap函数,与模板同名。所以出现swap情况下优先调用该函数。
一、标准库提供的全局std::swap(string& x, string& y)内部实现就是一行:
void swap(string& x, string& y) { x.swap(y); }- 标准库内部已经给
std::string写好了类内成员函数swap(); - 同时库中预实现了全局重载
std::swap(string&, string&); - 你直接写代码
std::swap(s1, s2)就能调用,底层自动执行s1.swap(s2) x.swap(y)代表:用对象 x 调用自身的成员 swap 函数,传入对象 y。
二、标准库里没有为你的自定义string类提前写好swap 重载
如果什么都不写,直接调用std::swap(s1,s2),会触发通用模板:
template<typename T> void swap(T& a, T& b) { T temp = a; // 完整拷贝整个字符串,复制堆上所有字符,低效 a = b; b = temp; }性能极差,违背 swap 轻量化设计。
三、想要让std::swap(s1,s2)高效交换你的自定义 string,必须自己实现类内成员 swap
// 写在你的自定义string类里面 void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }只要有这个成员函数,调用std::swap(s1,s2)时,编译器依靠 ADL 查找规则,优先调用该函数,会自动执行s1.swap(s2),编译器优先去bit命名空间、string类内调用模拟实现的成员函数 swap,和标准文档描述行为一致,只交换三个内置变量,O (1) 开销