C++的复制与拷贝构造函数

85 阅读1分钟

引言:又是有趣的一个知识点

一 开端

先上一段代码

class String
{
   friend std::ostream& operator<<(std::ostream& stream,const String& string);

    private:
    char* m_buffer;
    unsigned int m_size;

    public:
    String(const char* string){
        m_size = strlen(string)+1;
        m_buffer = new char[m_size];
        memcpy(m_buffer,string,m_size);
    }

    ~String(){
        delete[] m_buffer;
    }
};

std::ostream& operator<<(std::ostream& stream,const String& string)
{
    stream<<string.m_buffer;
    return stream;
}

int main(){
    String s1 = "abc";
    String s2 = s1;
    std::cout<< s1<<endl;
    std::cout<< s2<<endl;
    return 0;
}

这里我们会看到以下一个现象:

1.输出两个 “abc”
2.发生异常

企业微信截图_275f5718-fea4-4f14-8492-422cca065021.png

二 浅拷贝与深拷贝

上面的异常是因为 s1 和s2 在回收的时候执行析构函数时重复释放同一块内存导致。在执行 String s2 = s1 的时候,它会对 String 的成员变量m_buffer和m_size进行拷贝,m_size是值拷贝,而m_buffer是指针,s2 的m_buffer指向了和 s1 的 m_buffer同一块的内存地址。所以当我们回收内存的时候会出现这个异常。这就是浅拷贝了。那么我们要解决这个问题,就得使用深拷贝

class String{
   friend std::ostream& operator<<(std::ostream& stream,const String& string);

    private:
    char* m_buffer;
    unsigned int m_size;

    public:
    String(const char* string){
        m_size = strlen(string);
        m_buffer = new char[m_size+1];
        memcpy(m_buffer,string,m_size+1);
    }

    String(const String& other):m_size(other.m_size)
    {        
        std::cout<< "copy String"<<std::endl;
        m_buffer = new char[m_size+1]; //创建一个新的m_buffer,然后进行拷贝
        memcpy(m_buffer,other.m_buffer,m_size+1);
    }
    ~String(){
        delete[] m_buffer;
    }

    char& operator[](unsigned int index)
    {
        return m_buffer[index];
    }
};

//这里两个 Print 方法看看会有什么不同哦
// void PrintString(String string){
//     std::cout<<string <<endl;
// }

void PrintString(String& string){
    std::cout<<string <<endl;
}

std::ostream& operator<<(std::ostream& stream,const String& string)
{
    stream<<string.m_buffer;
    return stream;
}

int main(){
    String s1 = "abc";
    String s2 = s1;
    s2[2] ='d';
    PrintString(s1);
    PrintString(s2);
    return 0;
}

输出日志

copy String
abc
abd