施磊老师高级c++(一)

发布于:2025-03-19 ⋅ 阅读:(18) ⋅ 点赞:(0)

对象被优化后, 才是高效的c++编程


注意, 这节讲的, 有很多 和现代编译器的结果不同, 注意RVO的默认开启

1.对象使用背后调用了哪些方法

  1. 代码实例:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    class Test{
    public:
        Test(int a = 10) :ma(a)
        {
            cout << "Test()" << endl;
        }
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        Test(const Test& t) :ma(t.ma)
        {
            cout << "Test(const Test&)" << endl;
        }
        Test& operator=(const Test& t)
        {
            cout << "operator=" << endl;
            ma = t.ma;
            return *this;
        }
    private:
        int ma;
    };
    
    int main()
    {
        Test t1;
        Test t2(t1); // 拷贝构造
        Test t3 = t1; //拷贝构造
    
        //c++编译器对于对象构造的优化: 用临时对象生成新对象时,临时对象就不产生了, 直接构造新对象就行了
        Test t4 = Test(20);  // Test(20)临时对象,生存周期: 所在语句  
        //等价于
        Test t5(20);
        cout << "------------" << endl;
    
        t4 = t2;  // 赋值, 不是构造
    
        //operator=,  需要传参, 
        //这两是 显示生成临时对象
        t4 = Test(30);  // 赋值, 这个临时对象必须生成, 
        t4 = (Test)20; //int->Test(int), 编译器发现要转的类型里有int , 就可以编译器隐式转换, 
    
    
        // 隐式生成临时对象
        t4 = 30; //int->Test(int)
        cout << "------------" << endl;
    
    
        Test* p = &Test(50);  // 临时对象, 出了这个语句就没了, 析构了. 地址也就没了
        const Test& ref = Test(50);  // 引用临时对象, 需要常引用, vs版本高, 检查严格
        // 引用是可以的,  引用虽然和指针很像, 但实际是  起别名, 离开这个语句, 临时对象不会析构
        //引用在C++中是一个别名(alias),它本质上是对某个对象的另一个名字。
        //临时对象变为了 引用变量, 声明周期是整个函数里
    
    
        return 0;
    }
    
  2. 结论:指针指向临时变量是不安全的, 但是 引用 是安全的

  3. 代码示例: 各种情况

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    class Test {
    public:
        Test(int a=5, int b=5) : ma(a), mb(b) {
            cout << "Test(int, int)" << endl;
        }
        ~Test() {
            cout << "~Test()" << endl;
        }
        Test(const Test& t) : ma(t.ma), mb(t.mb) {
            cout << "Test(const Test&)" << endl;
        }
        Test& operator=(const Test& t) {
            cout << "operator=" << endl;
            ma = t.ma;
            mb = t.mb;
            return *this;
        }
    private:
        int ma;
        int mb;
    };
    
    Test t1(10, 10);  // 1. 全局变量先构造, 普通构造
    
    int main() {
        Test t2(20, 20);   // 3. 普通构造
        Test t3 = t2; // 4. 拷贝构造
        static Test t4 = Test(30, 30);  // 5. 静态局部变量, 程序运行到这里才 构造  临时对象被优化, 仅t4的普通构造    等价于 static Test t4(30, 30)
        t2 = Test(40, 40);  // 6. 显示生成临时对象 先临时对象普通构造, 再operator= 析构
        t2 = (Test)(50, 50); // 7. 隐式生成临时对象 先临时对象普通构造, 再operator= 析构
        t2 = 60;  //8. 隐式生成临时对象 先临时对象普通构造, 再operator= 析构
        Test* p1 = new Test(70, 70); // 9.指针, new了, 非临时对象, 普通构造 , 不析构, 没有delete
        Test* p2 = new Test[2];  // 10. 数组, 两次普通构造 , 不析构, 没有delete
        //Test* p3 = &Test(80, 80);  // 11. 指针, 普通构造 , 但是出了这句 就析构了  成为 悬空指针 会被警告, 无法编译执行
    
        const Test& p4 = Test(90, 90); //12. 引用, 普通构造, 出了这句不析构, 出了函数析构
        delete p1;  // 13. 析构 p1
        delete[] p2; // 14. 析构 p2,两次析构
    }               // 15. 12析构, 4析构, 3析构, 5析构, 静态局部变量在数据段, 程序结束才析构, 2析构, 1析构
    
    
    
    Test t5(100, 100); // 2. 全局变量先构造, 普通构造
    

2.函数调用过程中对象背后调用方法

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

class Test {
public:
    Test(int a = 10) :ma(a) {
        cout << "Test()" << endl;
    }
    ~Test() {
        cout << "~Test()" << endl;
    }
    Test(const Test& t) :ma(t.ma) {
        cout << "Test(const Test&)" << endl;
    }
    Test& operator=(const Test& t) {
        cout << "operator=" << endl;
        ma = t.ma;
        return *this;
    }

    int GetData()const {
        return ma;
    }
private:
    int ma;
};

Test GetObject(Test t) {
    int val = t.GetData();
    Test tmp(val);
    return tmp;  //不能返回 局部的或者临时对象的指针

    /*
    static Test tmp(val);
    return &tmp;
    */
}

int main() {
    Test t1;        // 1. 调用默认构造函数
    Test t2;        // 2. 调用默认构造函数
    t2 = GetObject(t1);  // 3. 调用拷贝构造函数(参数传递)
    // 4. 调用默认构造函数(创建 tmp)
    // 5. 调用拷贝构造函数(返回 tmp) 会返回一个临时对象, 这个不会被优化哈
    // 6. 析构 tmp
    // 7. 析构参数 t
    // 8. 调用赋值运算符(将返回值赋给 t2)
    // 9. 析构临时对象
    return 0;
    // 10. 析构 t2
    // 11. 析构 t1
}

Test()
Test()
Test(const Test&)
Test()
~Test()
operator=
~Test()
~Test()
~Test()

注意: 以上标注只是NRVO情况, 现在的编译器默认开启RVO----自己补充 会变为9个

//5和9  由于现在大多数默认启用了RVO, 将不会存在  RVO 在 C++17 之后变成“强制优化”
// RVO(Return Value Optimization,返回值优化)是 C++ 编译器的一种优化技术,用于减少临时对象的创建,提升程序性能。它的核心思想是 避免拷贝构造,直接在目标位置构造对象。

// RVO优化后
/*
Test GetObject(Test t) {
    int val = t.GetData();
    return Test(val);  // 直接构造在 t2 的内存位置上
}

*/

3.总结三条对象优化的规则

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

class Test {
public:
    Test(int a = 10) :ma(a) {
        cout << "Test()" << endl;
    }
    ~Test() {
        cout << "~Test()" << endl;
    }
    Test(const Test& t) :ma(t.ma) {
        cout << "Test(const Test&)" << endl;
    }
    Test& operator=(const Test& t) {
        cout << "operator=" << endl;
        ma = t.ma;
        return *this;
    }

    int GetData()const {
        return ma;
    }
private:
    int ma;
};

Test GetObject(Test& t) {  // 仅换为引用, 就减少了 t的拷贝构造和析构  
    int val = t.GetData();
    // Test tmp(val);
    //return tmp;  
    return Test(val);  // 返回临时对象, 会直接在main函数 构造临时对象   
    //这个在现代编译器无变化, RVO会默认开启
    //临时对象 优化 比较复杂, 先浅理解


}

int main() {
    Test t1;        
    Test t2 = GetObject(t1);       //而如果用临时对象 拷贝构造 新对象, 那么临时对象就不产生了, 直接构造新对象  减少为 4个, 直接调用构造, 也不需要 operator=
    return 0;

}


  1. 函数参数传递过程中, 对象 优先 按 引用传递, 不要 值传递, 会减少很多 构造析构

    //未开启RVO
    Test()
    Test()
    Test(const Test&) // t拷贝构造
    Test()  
    Test(const Test&)  
    ~Test() 
    ~Test() // t析构
    operator=  
    ~Test() 
    ~Test()  
    ~Test()  
    
    //变为
    
    Test()
    Test() 
    Test()  
    Test(const Test&)  
    ~Test() 
    operator=  
    ~Test()  
    ~Test()  
    ~Test()
    
  2. 当函数 返回对象的 时候, 应该返回一个 临时对象, 而不要返回 一个定义过得 对象—这个在现代编译器无变化, RVO会默认开启

    Test()
    Test() 
    Test()  
    Test(const Test&)  // 返回值的tmp 拷贝构造 给main里的 临时对象
    ~Test()  // 析构返回值的这个 tmp
    operator=  
    ~Test()  
    ~Test()  
    ~Test() 
    
    //变为
    
    Test()
    Test()
    Test()  // 返回临时对象, 会直接在main函数 构造临时对象
    operator=   
    ~Test()
    ~Test()
    ~Test()
    
  3. 当函数返回一个对象时,优先使用初始化方式接收返回值,而不是赋值方式。
    使用临时对象 直接 初始化 对象, 将会舍弃临时对象, 直接 使用默认构造

    Test()
    Test()
    Test() // 返回临时对象, 会直接在main函数 构造临时对象
    operator=   // 临时对象 operator= 赋值
    ~Test() // 析构临时对象
    ~Test()
    ~Test()
    
    //变为
    Test()
    Test()  // 直接默认构造 t2, 不要临时对象了
    ~Test()
    ~Test()
    

4.CMyString的代码问题

String类中间 会有大量的 new和 delete, 如果不做 对象优化, 效率会非常低!!!

5.添加带右值引用参数的拷贝构造和赋值函数

重点最后两个函数

#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
    // 构造函数
    String(const char* p = nullptr)
    {
        if (p != nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            cout << "new" << endl;
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            cout << "new" << endl;
            *_pstr = '\0';
        }
        cout << "String()" << endl;
    }

    // 析构函数
    ~String()
    {
        delete[] _pstr;
        cout << "delete" << endl;
        _pstr = nullptr;
        cout << "~String()" << endl;
    }

    // 拷贝构造函数
    String(const String& other)
    {
        _pstr = new char[strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(_pstr, other._pstr);
        cout << "String(const String)" << endl;
    }

    // 赋值运算符重载
    String& operator=(const String& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
        }
		cout << "operator=" << endl;
        return *this;
    }

     加法运算符重载--未优化, 多了一次new,delete
    //String operator+(const String& other) const
    //{
    //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
    //    strcpy(newtmp, _pstr);
    //    strcat(newtmp, other._pstr);
    //    String newString(newtmp);
    //    delete[]newtmp;
    //    return newString;
    //}

    // 加法运算符重载--小优化后
    String operator+(const String& other) const
    {
        String newString;
        newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(newString._pstr, _pstr);
        strcat(newString._pstr, other._pstr);
        return newString;
    }

    // 比较运算符重载
    bool operator>(const String& other) const
    {
        return strcmp(_pstr, other._pstr) > 0;
    }

    bool operator<(const String& other) const
    {
        return strcmp(_pstr, other._pstr) < 0;
    }

    bool operator==(const String& other) const
    {
        return strcmp(_pstr, other._pstr) == 0;
    }

    // 长度方法
    size_t length() const
    {
        return strlen(_pstr);
    }

    // 下标运算符重载
    char& operator[](size_t index)
    {
        return _pstr[index];
    }

    const char& operator[](size_t index) const
    {
        return _pstr[index];
    }

    // 输出运算符重载
    friend std::ostream& operator<<(std::ostream& os, const String& str)
    {
        os << str._pstr;
        return os;
    }

    // 输入运算符重载
    friend std::istream& operator>>(std::istream& is, String& str)
    {
        char buffer[1024];
        is >> buffer;
        str = String(buffer);
        return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
    }

    const char* c_str()const { return _pstr; }

private:
    char* _pstr;
};

String GetString(String& str)
{
    const char* pstr = str.c_str();
    String tmpstr(pstr);
    return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
	  //return String(pstr);   
}

int main()
{
    String str1 ="aaaaaaaaaa";
    String str2;
    str2 = GetString(str1);
    cout << str2.c_str() << endl;
    

    return 0;
}
  1. 在String类中, 开启RVO, 并不使用operator= 的构造,new,delete,析构 顺序

    new
    String()
    new
    String()
    new
    String()
    delete
    new
    operator=
    delete
    ~String()
    aaaaaaaaaa
    delete
    ~String()
    delete
    ~String()
    
  2. 回顾右值引用: ---- 右值是 没有名字(临时量)或者没内存
    普通引用只能引用左值, 且
    常引用 可以 引用 右值, 但不能修改

    右值引用 引用右值, 且能改变值

        int a = 10;
        int& b = a;
        cout << b << endl;
        //int&& c = a; // 这是不行的
        int&& c = 20;  // c可以改变临时量值
        c = 40;
    	int &f = c;
        cout << c << endl;
    
        int tmp = 20;
        int& d = tmp;   
        d = 30;
        cout << d << endl;
    
        const int& e = 20;  // 常引用可以 引用右值, 但不能修改 值
        //e = 10;
        cout << e << endl;
    
  3. 带右值引用参数的拷贝构造-------- 实际代码里 没用–RVO使得没有 拷贝构造了

    String(String&& other)   // 换成右值引用   
        {//临时对象进入
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
            cout << "String(String&&)" << endl;
        }
    
    
    
  4. 带右值引用参数的operator= -------- 这个在代码里是 实际有效的 — 减少一次 new

    String& operator=(String&& other)
        {
            if (this != &other) // 防止自赋值
            {
                delete[] _pstr;
                cout << "delete" << endl;
                _pstr = other._pstr;  // 直接指向同一个资源
            	other._pstr = nullptr;
            }
            return *this;
        }
    
  5. 总体代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    class String
    {
    public:
        // 构造函数
        String(const char* p = nullptr)
        {
            if (p != nullptr)
            {
                _pstr = new char[strlen(p) + 1];
                cout << "new" << endl;
                strcpy(_pstr, p);
            }
            else
            {
                _pstr = new char[1];
                cout << "new" << endl;
                *_pstr = '\0';
            }
            cout << "String()" << endl;
        }
    
        // 析构函数
        ~String()
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = nullptr;
            cout << "~String()" << endl;
        }
    
        // 左值引用拷贝构造函数
        String(const String& other)
        {
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
            cout << "String(const String)" << endl;
        }
        //右值引用拷贝构造
        String(String&& other)   // 换成右值引用   
        {//临时对象进入
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
            cout << "String(String&&)" << endl;
        }
    
        // 左值引用赋值运算符重载
        String& operator=(const String& other)
        {
            if (this != &other) // 防止自赋值
            {
                delete[] _pstr;
                cout << "delete" << endl;
                _pstr = new char[strlen(other._pstr) + 1];
                cout << "new" << endl;
                strcpy(_pstr, other._pstr);
            }
            cout << "operator=" << endl;
            return *this;
        }
    
        //右值引用赋值运算符重载
        String& operator=(String&& other)
        {
            if (this != &other) // 防止自赋值
            {
                delete[] _pstr;
                cout << "delete" << endl;
                _pstr = other._pstr;  // 直接指向同一个资源
                other._pstr = nullptr;
            }
            cout << "operator=&&" << endl;
            return *this;
        }
    
         加法运算符重载--未优化, 多了一次new,delete
        //String operator+(const String& other) const
        //{
        //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        //    strcpy(newtmp, _pstr);
        //    strcat(newtmp, other._pstr);
        //    String newString(newtmp);
        //    delete[]newtmp;
        //    return newString;
        //}
    
        // 加法运算符重载--小优化后
        String operator+(const String& other) const
        {
            String newString;
            newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(newString._pstr, _pstr);
            strcat(newString._pstr, other._pstr);
            return newString;
        }
    
        // 比较运算符重载
        bool operator>(const String& other) const
        {
            return strcmp(_pstr, other._pstr) > 0;
        }
    
        bool operator<(const String& other) const
        {
            return strcmp(_pstr, other._pstr) < 0;
        }
    
        bool operator==(const String& other) const
        {
            return strcmp(_pstr, other._pstr) == 0;
        }
    
        // 长度方法
        size_t length() const
        {
            return strlen(_pstr);
        }
    
        // 下标运算符重载
        char& operator[](size_t index)
        {
            return _pstr[index];
        }
    
        const char& operator[](size_t index) const
        {
            return _pstr[index];
        }
    
        // 输出运算符重载
        friend std::ostream& operator<<(std::ostream& os, const String& str)
        {
            os << str._pstr;
            return os;
        }
    
        // 输入运算符重载
        friend std::istream& operator>>(std::istream& is, String& str)
        {
            char buffer[1024];
            is >> buffer;
            str = String(buffer);
            return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
        }
    
        const char* c_str()const { return _pstr; }
    
    private:
        char* _pstr;
    };
    
    String GetString(String& str)
    {
        const char* pstr = str.c_str();
        String tmpstr(pstr);
        return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
        //return String(pstr);   
    }
    
    int main()
    {
        String str1 ("aaaaaaaaaa");
        String str2;
        str2 = GetString(str1);
    
        cout << str2.c_str() << endl;
        
        return 0;
    }
    
    new
    String()
    new
    String()
    new
    String()
    delete
    operator=&&
    delete
    ~String()
    aaaaaaaaaa
    delete
    ~String()
    delete
    ~String()
    

6.String类在vector上的应用–面试题

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
    // 构造函数
    String(const char* p = nullptr)
    {
        if (p != nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            cout << "new" << endl;
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            cout << "new" << endl;
            *_pstr = '\0';
        }
        cout << "String()" << endl;
    }

    // 析构函数
    ~String()
    {
        delete[] _pstr;
        cout << "delete" << endl;
        _pstr = nullptr;
        cout << "~String()" << endl;
    }

    // 左值引用拷贝构造函数
    String(const String& other)
    {
        _pstr = new char[strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(_pstr, other._pstr);
        cout << "String(const String)" << endl;
    }
    //右值引用拷贝构造
    String(String&& other)   // 换成右值引用   
    {//临时对象进入
        _pstr = other._pstr;  // 直接指向同一个资源
        other._pstr = nullptr;
        cout << "String(String&&)" << endl;
    }

    // 左值引用赋值运算符重载
    String& operator=(const String& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
        }
        cout << "operator=" << endl;
        return *this;
    }

    //右值引用赋值运算符重载
    String& operator=(String&& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
        }
        cout << "operator=&&" << endl;
        return *this;
    }

     加法运算符重载--未优化, 多了一次new,delete
    //String operator+(const String& other) const
    //{
    //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
    //    strcpy(newtmp, _pstr);
    //    strcat(newtmp, other._pstr);
    //    String newString(newtmp);
    //    delete[]newtmp;
    //    return newString;
    //}

    // 加法运算符重载--小优化后
    String operator+(const String& other) const
    {
        String newString;
        newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(newString._pstr, _pstr);
        strcat(newString._pstr, other._pstr);
        return newString;
    }

    // 比较运算符重载
    bool operator>(const String& other) const
    {
        return strcmp(_pstr, other._pstr) > 0;
    }

    bool operator<(const String& other) const
    {
        return strcmp(_pstr, other._pstr) < 0;
    }

    bool operator==(const String& other) const
    {
        return strcmp(_pstr, other._pstr) == 0;
    }

    // 长度方法
    size_t length() const
    {
        return strlen(_pstr);
    }

    // 下标运算符重载
    char& operator[](size_t index)
    {
        return _pstr[index];
    }

    const char& operator[](size_t index) const
    {
        return _pstr[index];
    }

    // 输出运算符重载
    friend std::ostream& operator<<(std::ostream& os, const String& str)
    {
        os << str._pstr;
        return os;
    }

    // 输入运算符重载
    friend std::istream& operator>>(std::istream& is, String& str)
    {
        char buffer[1024];
        is >> buffer;
        str = String(buffer);
        return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
    }

    const char* c_str()const { return _pstr; }

private:
    char* _pstr;
};

String GetString(String& str)
{
    const char* pstr = str.c_str();
    String tmpstr(pstr);
    return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
    //return String(pstr);   
}


int main()
{
    String str1 = "aaaaaaaaaa";
    vector<String> vec;
    vec.reserve(10);
    vec.push_back(str1);  //
    vec.push_back(String("bbbb"));
    return 0;
}


面试题: 问 两次push_back 分别是 使用了什么拷贝构造?!!!
一次左值引用拷贝, 一次右值引用拷贝
右值引用相比 左值引用, 更高效

new
String()
new
String(const String)
new
String()
String(String&&)
delete
~String()
delete
~String()
delete
~String()
delete
~String()

7.move移动语义和forword类型完美转发

move移动语义的作用

代码:

上一节代码里, 加上 很早之前写的 Vector类: 添加一个push_back的右值引用

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


#include <iostream>
using namespace std;

template<typename T>
struct Allocator
{
    T* allocate(size_t size)// 开辟内存
    {
        return (T*)malloc(sizeof(T) * size);
    }

    void deallocate(void* p) // 释放内存
    {
        free(p);
    }

    void  construct(T* p, const T& val) //对象构造
    {
        new (p) T(val); //定位new
        /*
        作用是在一块已经分配好的内存上构造一个对象,而不是通过 new 运算符动态分配内存。

p 是一个指针,指向一块预先分配好的内存。

T(val) 表示调用类型 T 的构造函数,并传递参数 val。

new (p) T(val) 的意思是在 p 指向的内存地址上构造一个 T 类型的对象,并调用构造函数 T(val)。

        */
    }

    void destroy(T* p) // 对象析构
    {
        p->~T(); //~T()代表T类型的析构函数
    }
};

template<typename T, typename Alloc = Allocator<T>>  //Alloc默认是Allocator<T>
class Vector
{
private:
    T* _first;//数组起始,与数组名
    T* _last;//数组最后位置的下一个
    T* _end;//空间的后面位置
    Alloc _allocator;//定义容器空间配置对象

    void expand() //二倍扩容
    {
        int size = _last - _first;
        //T* ptmp = new T[2 * size];
        T* ptmp = _allocator.allocate(2 * size);

        for (int i = 0; i < size; i++)
        {

            //ptmp[i] = _first[i];
            _allocator.construct(ptmp + i, _first[i]);
        }
        //delete[]_first;
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _first = ptmp;
        _last = _first + size;
        _end = _first + 2 * size;


    }

public:
    Vector(int size = 10)
    {
        //_first = new T[size];
        // 只开辟内存
        _first = _allocator.allocate(size);
        _last = _first;
        _end = _first + size;
    }

    ~Vector()
    {
        //delete[]_first;
        // 析构有效的元素并释放内存
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _allocator.deallocate(_first); //释放堆上的数组内存
        _first = _last = _end = nullptr;
    }

    Vector(const Vector<T>& src)
    {
        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
    }

    Vector<T>& operator=(const Vector<T>& src)
    {
        if (this == &src)
        {
            return *this;
        }

        //delete[]_first;

        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }

        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
        return *this;

    }
	
    //添加右值引用push_back
    void push_back(T&& val) //向容器末尾添加元素
    {
        if (full())
        {
            expand();
        }
        _allocator.construct(_last, val);
        _last++;
    }
    
    
    void push_back(const T& val) //向容器末尾添加元素
    {
        if (full())
        {
            expand();
        }
        //*_last++ = val;
        _allocator.construct(_last, val);
        _last++;
    }

    void pop_back() //向容器末尾删除元素
    {
        if (empty())
        {
            return;
        }
        --_last;
        _allocator.destroy(_last);
    }

    bool full()const
    {
        return _last == _end;
    }

    bool empty()const
    {
        return _last == _first;
    }

    T back()const // 返回末尾元素
    {
        return *(_last - 1);// *(--_last)错误的, 本函数const方法, 不能修改成员变量, _last-1是偏移量, --会改变last值
    }
};


class String
{
public:
    // 构造函数
    String(const char* p = nullptr)
    {
        if (p != nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            cout << "new" << endl;
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            cout << "new" << endl;
            *_pstr = '\0';
        }
        cout << "String()" << endl;
    }

    // 析构函数
    ~String()
    {
        delete[] _pstr;
        cout << "delete" << endl;
        _pstr = nullptr;
        cout << "~String()" << endl;
    }

    // 左值引用拷贝构造函数
    String(const String& other)
    {
        _pstr = new char[strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(_pstr, other._pstr);
        cout << "String(const String)" << endl;
    }
    //右值引用拷贝构造
    String(String&& other)   // 换成右值引用   
    {//临时对象进入
        _pstr = other._pstr;  // 直接指向同一个资源
        other._pstr = nullptr;
        cout << "String(String&&)" << endl;
    }

    // 左值引用赋值运算符重载
    String& operator=(const String& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
        }
        cout << "operator=" << endl;
        return *this;
    }

    //右值引用赋值运算符重载
    String& operator=(String&& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
        }
        cout << "operator=&&" << endl;
        return *this;
    }

     加法运算符重载--未优化, 多了一次new,delete
    //String operator+(const String& other) const
    //{
    //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
    //    strcpy(newtmp, _pstr);
    //    strcat(newtmp, other._pstr);
    //    String newString(newtmp);
    //    delete[]newtmp;
    //    return newString;
    //}

    // 加法运算符重载--小优化后
    String operator+(const String& other) const
    {
        String newString;
        newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(newString._pstr, _pstr);
        strcat(newString._pstr, other._pstr);
        return newString;
    }

    // 比较运算符重载
    bool operator>(const String& other) const
    {
        return strcmp(_pstr, other._pstr) > 0;
    }

    bool operator<(const String& other) const
    {
        return strcmp(_pstr, other._pstr) < 0;
    }

    bool operator==(const String& other) const
    {
        return strcmp(_pstr, other._pstr) == 0;
    }

    // 长度方法
    size_t length() const
    {
        return strlen(_pstr);
    }

    // 下标运算符重载
    char& operator[](size_t index)
    {
        return _pstr[index];
    }

    const char& operator[](size_t index) const
    {
        return _pstr[index];
    }

    // 输出运算符重载
    friend std::ostream& operator<<(std::ostream& os, const String& str)
    {
        os << str._pstr;
        return os;
    }

    // 输入运算符重载
    friend std::istream& operator>>(std::istream& is, String& str)
    {
        char buffer[1024];
        is >> buffer;
        str = String(buffer);
        return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
    }

    const char* c_str()const { return _pstr; }

private:
    char* _pstr;
};

String GetString(String& str)
{
    const char* pstr = str.c_str();
    String tmpstr(pstr);
    return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
    //return String(pstr);   
}


int main()
{
    String str1 = "aaaaaaaaaa";
    Vector<String> vec;
    vec.push_back(str1);  //
    vec.push_back(String("bbbb"));
    return 0;
}


new
String()
new
String(const String)
new
String()
new
String(const String)
delete
~String()
delete
~String()
delete
~String()
delete
~String()
**问题: **

发现没有使用 到 右值引用

//添加右值引用push_back
    void push_back(const T&& val) //向容器末尾添加元素
    {
        if (full())
        {
            expand();
        }
        _allocator.construct(_last, val);
        _last++;
    }

是因为, 这里面 给 _allocator.construct()的val 还是左值引用

解决办法:
  1. move移动语义, 强转成 右值引用类型

    _allocator.construct(_last, val);
    //变为
    _allocator.construct(_last, move(val));   //std::move
    
    
    
  2. 添加 construct 右值引用

    //右值引用 construct  里面的 也需要 move val
    void  construct(T* p, T&& val) //对象构造
    {
        new (p) T(move(val)); 
    }
    
最终代码:

----- 注意. 右值引用不加const

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


#include <iostream>
using namespace std;

template<typename T>
struct Allocator
{
    T* allocate(size_t size)// 开辟内存
    {
        return (T*)malloc(sizeof(T) * size);
    }

    void deallocate(void* p) // 释放内存
    {
        free(p);
    }

    void  construct(T* p, const T& val) //对象构造
    {
        new (p) T(val); //定位new
        /*
        作用是在一块已经分配好的内存上构造一个对象,而不是通过 new 运算符动态分配内存。

p 是一个指针,指向一块预先分配好的内存。

T(val) 表示调用类型 T 的构造函数,并传递参数 val。

new (p) T(val) 的意思是在 p 指向的内存地址上构造一个 T 类型的对象,并调用构造函数 T(val)。

        */
    }
    //右值引用 construct  里面的 也需要 move val
    void  construct(T* p, T&& val) //对象构造
    {
        new (p) T(move(val)); 
    }

    void destroy(T* p) // 对象析构
    {
        p->~T(); //~T()代表T类型的析构函数
    }
};

template<typename T, typename Alloc = Allocator<T>>  //Alloc默认是Allocator<T>
class Vector
{
private:
    T* _first;//数组起始,与数组名
    T* _last;//数组最后位置的下一个
    T* _end;//空间的后面位置
    Alloc _allocator;//定义容器空间配置对象

    void expand() //二倍扩容
    {
        int size = _last - _first;
        //T* ptmp = new T[2 * size];
        T* ptmp = _allocator.allocate(2 * size);

        for (int i = 0; i < size; i++)
        {

            //ptmp[i] = _first[i];
            _allocator.construct(ptmp + i, _first[i]);
        }
        //delete[]_first;
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _first = ptmp;
        _last = _first + size;
        _end = _first + 2 * size;


    }

public:
    Vector(int size = 10)
    {
        //_first = new T[size];
        // 只开辟内存
        _first = _allocator.allocate(size);
        _last = _first;
        _end = _first + size;
    }

    ~Vector()
    {
        //delete[]_first;
        // 析构有效的元素并释放内存
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _allocator.deallocate(_first); //释放堆上的数组内存
        _first = _last = _end = nullptr;
    }

    Vector(const Vector<T>& src)
    {
        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
    }

   

    Vector<T>& operator=(const Vector<T>& src)
    {
        if (this == &src)
        {
            return *this;
        }

        //delete[]_first;

        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }

        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
        return *this;

    }
    //添加右值引用push_back
    void push_back(T&& val) //向容器末尾添加元素
    {
        if (full())
        {
            expand();
        }
        _allocator.construct(_last, move(val));
        _last++;
    }
    void push_back(const T& val) //向容器末尾添加元素
    {
        if (full())
        {
            expand();
        }
        //*_last++ = val;
        _allocator.construct(_last, val);
        _last++;
    }

    void pop_back() //向容器末尾删除元素
    {
        if (empty())
        {
            return;
        }
        --_last;
        _allocator.destroy(_last);
    }

    bool full()const
    {
        return _last == _end;
    }

    bool empty()const
    {
        return _last == _first;
    }

    T back()const // 返回末尾元素
    {
        return *(_last - 1);// *(--_last)错误的, 本函数const方法, 不能修改成员变量, _last-1是偏移量, --会改变last值
    }
};


class String
{
public:
    // 构造函数
    String(const char* p = nullptr)
    {
        if (p != nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            cout << "new" << endl;
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            cout << "new" << endl;
            *_pstr = '\0';
        }
        cout << "String()" << endl;
    }

    // 析构函数
    ~String()
    {
        delete[] _pstr;
        cout << "delete" << endl;
        _pstr = nullptr;
        cout << "~String()" << endl;
    }

    // 左值引用拷贝构造函数
    String(const String& other)
    {
        _pstr = new char[strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(_pstr, other._pstr);
        cout << "String(const String)" << endl;
    }
    //右值引用拷贝构造
    String(String&& other)   // 换成右值引用   
    {//临时对象进入
        _pstr = other._pstr;  // 直接指向同一个资源
        other._pstr = nullptr;
        cout << "String(String&&)" << endl;
    }

    // 左值引用赋值运算符重载
    String& operator=(const String& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
        }
        cout << "operator=" << endl;
        return *this;
    }

    //右值引用赋值运算符重载
    String& operator=(String&& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
        }
        cout << "operator=&&" << endl;
        return *this;
    }

     加法运算符重载--未优化, 多了一次new,delete
    //String operator+(const String& other) const
    //{
    //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
    //    strcpy(newtmp, _pstr);
    //    strcat(newtmp, other._pstr);
    //    String newString(newtmp);
    //    delete[]newtmp;
    //    return newString;
    //}

    // 加法运算符重载--小优化后
    String operator+(const String& other) const
    {
        String newString;
        newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(newString._pstr, _pstr);
        strcat(newString._pstr, other._pstr);
        return newString;
    }

    // 比较运算符重载
    bool operator>(const String& other) const
    {
        return strcmp(_pstr, other._pstr) > 0;
    }

    bool operator<(const String& other) const
    {
        return strcmp(_pstr, other._pstr) < 0;
    }

    bool operator==(const String& other) const
    {
        return strcmp(_pstr, other._pstr) == 0;
    }

    // 长度方法
    size_t length() const
    {
        return strlen(_pstr);
    }

    // 下标运算符重载
    char& operator[](size_t index)
    {
        return _pstr[index];
    }

    const char& operator[](size_t index) const
    {
        return _pstr[index];
    }

    // 输出运算符重载
    friend std::ostream& operator<<(std::ostream& os, const String& str)
    {
        os << str._pstr;
        return os;
    }

    // 输入运算符重载
    friend std::istream& operator>>(std::istream& is, String& str)
    {
        char buffer[1024];
        is >> buffer;
        str = String(buffer);
        return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
    }

    const char* c_str()const { return _pstr; }

private:
    char* _pstr;
};

String GetString(String& str)
{
    const char* pstr = str.c_str();
    String tmpstr(pstr);
    return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
    //return String(pstr);   
}


int main()
{
    String str1 = "aaaaaaaaaa";
    Vector<String> vec;
    vec.push_back(str1);  //
    vec.push_back(String("bbbb"));
    return 0;
}


new
String()
new
String(const String)
new
String()
String(String&&)
delete
~String()
delete
~String()
delete
~String()
delete
~String()

forward完美转发内容

引用折叠

引用折叠(Reference Collapsing)是 C++11 引入的一个规则,用于处理模板和类型推导中涉及引用的复杂情况。它是实现完美转发(Perfect Forwarding)和通用引用(Universal Reference)的基础。

template <typename T>
void foo(T&& arg) {
    // T 的类型和 arg 的类型由引用折叠规则决定
}
  • 如果传递一个左值(如 int x; foo(x);),T 推导为 int&arg 的类型为 int& &&,折叠为 int&
  • 如果传递一个右值(如 foo(42);),T 推导为 intarg 的类型为 int&&
push_back模板 – 直接替代左右值引用push_back
 template<typename Ty>  // 函数模板的类型推演 + 引用折叠
 void push_back(Ty&& val) 
 {
     if (full())
     {
         expand();
     }
     _allocator.construct(_last, val);   // 这里还有问题, val传进去会被认为是左值
     _last++;
 }

forward完美转发

完美转发(Perfect Forwarding)是 C++11 引入的一项重要特性,用于在函数模板中保留参数的值类别(左值或右值),并将其原封不动地传递给其他函数。完美转发的核心目标是避免不必要的拷贝和移动操作,同时正确处理左值和右值。

完美转发通过以下两个特性实现:

  1. 通用引用(Universal Reference)

    • 使用 T&& 作为参数类型,可以根据传入参数的值类别推导出正确的类型(左值引用或右值引用)。
  2. std::forward

    • std::forward 是一个工具函数,用于保留参数的值类别。
    • 如果参数是左值,std::forward 返回左值引用。
    • 如果参数是右值,std::forward 返回右值引用。
  3. 最终,push_back 修改为

    template<typename Ty>  // 函数模板的类型推演 + 引用折叠
    void push_back(Ty&& val) 
    {
        if (full())
        {
            expand();
        }
        _allocator.construct(_last, forward<Ty>(val)); // std::forword(val) 类型的完美转发
        _last++;
    }
    
    
带有完美转发的 完整代码

construct 也可以使用模板, 不写两次

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


#include <iostream>
using namespace std;

template<typename T>
struct Allocator
{
    T* allocate(size_t size)// 开辟内存
    {
        return (T*)malloc(sizeof(T) * size);
    }

    void deallocate(void* p) // 释放内存
    {
        free(p);
    }

//    void  construct(T* p, const T& val) //对象构造
//    {
//        new (p) T(val); //定位new
//        /*
//        作用是在一块已经分配好的内存上构造一个对象,而不是通过 new 运算符动态分配内存。
//
//p 是一个指针,指向一块预先分配好的内存。
//
//T(val) 表示调用类型 T 的构造函数,并传递参数 val。
//
//new (p) T(val) 的意思是在 p 指向的内存地址上构造一个 T 类型的对象,并调用构造函数 T(val)。
//
//        */
//    }
//    右值引用 construct  里面的 也需要 move val
//    //void  construct(T* p, T&& val) //对象构造
//    //{
//    //    new (p) T(move(val)); 
//    //}

    //模板, 引用折叠
    template<typename Ty>
    void  construct(T* p, Ty&& val) //对象构造
    {
        new (p) T(forward<Ty>(val));  // 注意Ty和 T
    }

    void destroy(T* p) // 对象析构
    {
        p->~T(); //~T()代表T类型的析构函数
    }
};

template<typename T, typename Alloc = Allocator<T>>  //Alloc默认是Allocator<T>
class Vector
{
private:
    T* _first;//数组起始,与数组名
    T* _last;//数组最后位置的下一个
    T* _end;//空间的后面位置
    Alloc _allocator;//定义容器空间配置对象

    void expand() //二倍扩容
    {
        int size = _last - _first;
        //T* ptmp = new T[2 * size];
        T* ptmp = _allocator.allocate(2 * size);

        for (int i = 0; i < size; i++)
        {

            //ptmp[i] = _first[i];
            _allocator.construct(ptmp + i, _first[i]);
        }
        //delete[]_first;
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _first = ptmp;
        _last = _first + size;
        _end = _first + 2 * size;


    }

public:
    Vector(int size = 10)
    {
        //_first = new T[size];
        // 只开辟内存
        _first = _allocator.allocate(size);
        _last = _first;
        _end = _first + size;
    }

    ~Vector()
    {
        //delete[]_first;
        // 析构有效的元素并释放内存
        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }
        _allocator.deallocate(_first); //释放堆上的数组内存
        _first = _last = _end = nullptr;
    }

    Vector(const Vector<T>& src)
    {
        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
    }

   

    Vector<T>& operator=(const Vector<T>& src)
    {
        if (this == &src)
        {
            return *this;
        }

        //delete[]_first;

        for (T* p = _first; p != _last; ++p)
        {
            _allocator.destroy(p); //析构_first指针指向的数组的有效元素
        }

        int size = src._end - src._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = src._last - src._first;
        for (int i = 0; i < len; i++)
        {
            //_first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
        return *this;

    }
    template<typename Ty>  // 函数模板的类型推演 + 引用折叠
    void push_back(Ty&& val) 
    {
        if (full())
        {
            expand();
        }
        _allocator.construct(_last, forward<Ty>(val)); // std::forword(val) 类型的完美转发
        _last++;
    }

    添加右值引用push_back
    //void push_back(T&& val) //向容器末尾添加元素
    //{
    //    if (full())
    //    {
    //        expand();
    //    }
    //    _allocator.construct(_last, move(val));
    //    _last++;
    //}
    //void push_back(const T& val) //向容器末尾添加元素
    //{
    //    if (full())
    //    {
    //        expand();
    //    }
    //    //*_last++ = val;
    //    _allocator.construct(_last, val);
    //    _last++;
    //}

    void pop_back() //向容器末尾删除元素
    {
        if (empty())
        {
            return;
        }
        --_last;
        _allocator.destroy(_last);
    }

    bool full()const
    {
        return _last == _end;
    }

    bool empty()const
    {
        return _last == _first;
    }

    T back()const // 返回末尾元素
    {
        return *(_last - 1);// *(--_last)错误的, 本函数const方法, 不能修改成员变量, _last-1是偏移量, --会改变last值
    }
};


class String
{
public:
    // 构造函数
    String(const char* p = nullptr)
    {
        if (p != nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            cout << "new" << endl;
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            cout << "new" << endl;
            *_pstr = '\0';
        }
        cout << "String()" << endl;
    }

    // 析构函数
    ~String()
    {
        delete[] _pstr;
        cout << "delete" << endl;
        _pstr = nullptr;
        cout << "~String()" << endl;
    }

    // 左值引用拷贝构造函数
    String(const String& other)
    {
        _pstr = new char[strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(_pstr, other._pstr);
        cout << "String(const String)" << endl;
    }
    //右值引用拷贝构造
    String(String&& other)   // 换成右值引用   
    {//临时对象进入
        _pstr = other._pstr;  // 直接指向同一个资源
        other._pstr = nullptr;
        cout << "String(String&&)" << endl;
    }

    // 左值引用赋值运算符重载
    String& operator=(const String& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = new char[strlen(other._pstr) + 1];
            cout << "new" << endl;
            strcpy(_pstr, other._pstr);
        }
        cout << "operator=" << endl;
        return *this;
    }

    //右值引用赋值运算符重载
    String& operator=(String&& other)
    {
        if (this != &other) // 防止自赋值
        {
            delete[] _pstr;
            cout << "delete" << endl;
            _pstr = other._pstr;  // 直接指向同一个资源
            other._pstr = nullptr;
        }
        cout << "operator=&&" << endl;
        return *this;
    }

     加法运算符重载--未优化, 多了一次new,delete
    //String operator+(const String& other) const
    //{
    //    char* newtmp = new char[strlen(_pstr) + strlen(other._pstr) + 1];
    //    strcpy(newtmp, _pstr);
    //    strcat(newtmp, other._pstr);
    //    String newString(newtmp);
    //    delete[]newtmp;
    //    return newString;
    //}

    // 加法运算符重载--小优化后
    String operator+(const String& other) const
    {
        String newString;
        newString._pstr = new char[strlen(_pstr) + strlen(other._pstr) + 1];
        cout << "new" << endl;
        strcpy(newString._pstr, _pstr);
        strcat(newString._pstr, other._pstr);
        return newString;
    }

    // 比较运算符重载
    bool operator>(const String& other) const
    {
        return strcmp(_pstr, other._pstr) > 0;
    }

    bool operator<(const String& other) const
    {
        return strcmp(_pstr, other._pstr) < 0;
    }

    bool operator==(const String& other) const
    {
        return strcmp(_pstr, other._pstr) == 0;
    }

    // 长度方法
    size_t length() const
    {
        return strlen(_pstr);
    }

    // 下标运算符重载
    char& operator[](size_t index)
    {
        return _pstr[index];
    }

    const char& operator[](size_t index) const
    {
        return _pstr[index];
    }

    // 输出运算符重载
    friend std::ostream& operator<<(std::ostream& os, const String& str)
    {
        os << str._pstr;
        return os;
    }

    // 输入运算符重载
    friend std::istream& operator>>(std::istream& is, String& str)
    {
        char buffer[1024];
        is >> buffer;
        str = String(buffer);
        return is;  // 支持链式操作  例如: cin>>a>>b,第一次cin>>a返回cin, 即后面的变为 cin>>b
    }

    const char* c_str()const { return _pstr; }

private:
    char* _pstr;
};

String GetString(String& str)
{
    const char* pstr = str.c_str();
    String tmpstr(pstr);
    return tmpstr;   // 不开启RVO时, main函数这里会拷贝构造临时对象
    //return String(pstr);   
}



int main()
{
    String str1 = "aaaaaaaaaa";
    Vector<String> vec;
    vec.push_back(str1);  //
    vec.push_back(String("bbbb"));
    return 0;
}


总结

move 是为了得到 右值类型
forward 是为了 能够正确识别 左值和右值类型—一般配合模板使用,很方便,不需要写那么多重载

模板中的 引用折叠 很好的解决了 重载麻烦的问题

很灵活的!!!