浅拷贝:以string类为例 c++浅拷贝以及浅拷贝的解决方案 当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。默认拷贝构造属于浅拷贝,相当于两个指针变量指向了同一块地址空间,调用析构函数时,会delete两次,所以在第二次delete时会发生中断(无法寻址地址)

//浅拷贝
class string
    {
    private:
        char* _str;
    public:
        string(char* str = "")//构造函数
        {
            if (nullptr == str)
            {
                str = "";
            }
            _str = new char[strlen(str) + 1];
            strcpy(_str,str);
        }
        string(const string& s)//拷贝构造
            :_str(s._str)
        {
        }
        string operator =(string& s)//赋值构造
        {
            _str = s._str;
            return *this;
        }
        ~string()
        {
            if (_str)
            {
                delete _str;
                _str = nullptr;
            }
        }
    };

c++浅拷贝以及浅拷贝的解决方案 解决方案1.传统深拷贝 在拷贝构造中重新开辟空间,然后把被拷贝对象中的元素拷贝到新空间中

//缺点:需要多次开辟空间,代码冗余 //优点:可读性高

class string
{
private:
    char* _str;
public:
    string(char* str = "")
    {
        if (str == nullptr)
        {
            str = "";
        }
        _str = new char[strlen(str) + 1];
        strcpy(_str,str);
    }
    string(const string& s)
        :_str(new char[strlen(s._str)+1])
    {
        strcpy(_str,s._str);
    }
    string& operator=(string& s)
    {
        if (this != &s)
        {
            char* temp = new char[strlen(s._str) + 1];
            strcpy(temp,s._str);
            delete _str;
            _str = temp;
        }
        return *this;
    }
    ~string()
    {
        if (_str)
        {
            delete _str;
            _str = nullptr;
        }
    }
};

解决方案2.精简深拷贝 1.传址,在方法中重新定义一个对象接受被拷贝对象元素,然后交换临时对象和需要拷贝对象的地址 2.传值,直接交换临时对象和需要拷贝对象的地址

//优点:代码高效 缺点:可读性不高

class string
    {
    private:
        char* _str;
    public:
        string(char* str="")
        {
            if (str == nullptr)
            {
                str = "";
            }
            _str = new char[strlen(str) + 1];
            strcpy(_str,str);
        }
        string(const string& s)
            :_str(nullptr)
        {
            string temp(s._str);
            swap(_str,temp._str);
        }
        /*string& operator=(const string& s)
        {
            if (this != &s)
            {
                string temp = s._str;
                swap(_str,temp._str);
            }
            return *this;
        }*/
        string& operator=(string s)//直接改变指向(传值:临时变量)
        {
            swap(_str,s._str);
            return *this;
        }
        ~string()
        {
            if (_str)
            {
                delete[] _str;
                _str = nullptr;
            }
        }
    };

解决方案3.浅拷贝+计数(相当于出门时,最后一个人才“关门”,进出门的人进行计数) 计数:定义一个成员_count,在普通构造函数中直接初始化为1,而进行拷贝构造时判断被拷贝对象的成员_count++,而需要拷贝对象的成员_count是否为0,(如果为0,则需要拷贝对象成员_count++,如果>0,则则需要拷贝对象成员_count--),最后析构函数中对象_count成员为0时,调用delete

class |string
    {
    private :
        char* _str;
        int* _count;
    public :
        string(char* str="")
            : _count(new int(1))//调用普通构造:_count初始化为1
            , _str(new char[strlen(str) + 1])
        {
            if (str == nullptr)
            {
                str = "";
            }

            strcpy(_str,str);
        }
        string(const string& s)
            :_str(s._str)
            , _count(s._count)
        {
            ++(*_count);
        }
        string operator=(string& s)
        {
            if (this != &s)
            {
                if (0 == --(*_count))
                {
                    delete[] _str;
                    delete _count;
                    _str = nullptr;
                    _count = nullptr;
                }
                _str = s._str;
                _count = s._count;
                ++(*_count);
            }
            return *this;
        }
        ~string()
        {
            if (_str&&0 == --(*_count))
            {
                delete[] _str;
                delete _count;
                _str = nullptr;
                _count = nullptr;
            }
        }
        char& operator[](size_t index)
        {
            if ((*_count) > 1)
            {
                string temp(_str);
                this->swap(temp);
            }
            return _str[index];
        }
        void swap(string& s)
        {
            std::swap(_str,s._str);
            std::swap(_count,s._count);
        }
        const char& operator[](size_t index)const
        {
            return _str[index];
        }
    };