深浅拷贝/写时拷贝

在我们实现string类的时候会需要用到字符串的拷贝,会有一下三种方法:浅拷贝、深拷贝、写实拷贝

浅拷贝

这里写图片描述
浅拷贝的实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

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

void test()
{
    String s1("hello world");
    String s2(s1);

}
int main()
{
    test();
    return 0;
}

调试结果
由上图可知两个指针指向了同一块内存,因此在调用析构函数时,会重复调用两次,导致出错。

深拷贝:

这里写图片描述
由上图可知,深拷贝即是重新开辟一块与原数据块一样大小的内存空间,将s1内容拷贝,这样s1和s2指向各自的空间。
深拷贝的实现:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class String
{
public:
    String(const char*str)
        :_str(new char[strlen(str) + 1])
    {
        strcpy(_str, str);
    }
    String(const String&str)
        :_str(new char[strlen(str._str)+1])
    {
        strcpy(_str, str._str);
    }
    String operator=(const String &str)
    {
        if (this != &str)
        {
            delete[]_str;
            _str = new char[strlen(str._str) + 1];
            strcpy(_str, str._str);
        }
        return *this;
    }

    ~String()
    {
        if (_str)
            delete[]_str;
    }
private:
    char*_str;
};

void test()
{
    String s1("hello world");
    String s2(s1);
}
int main()
{
    test();
    return 0;
}

这里写图片描述
此时两个指针便会指向不同的内存,不存在重复析构的问题。

写实拷贝

这里写图片描述
由上图我们可知,当s1开辟空间的时候,用前四个字节来存放ReferenceCount

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class String
{
public:
    String(const char*str)
        :_str(new char[strlen(str) + 5])
    {
        _str = _str + 4;
        strcpy(_str, str);
        RefCount() = 1;
    }
    int &RefCount()
    {
        return *((int*)(_str - 4));
    }
    String(const String&str)
        :_str(str._str)
    {
        RefCount()++;
    }
    String operator=(const String &str)
    {
        if (this != &str)
        {
            if (RefCount() == 1)
            {
                delete[](_str-4);
            }
            _str = str._str;
            RefCount()++;
        }
        return *this;
    }

    ~String()
    {
        if (RefCount()== 1)
            delete[](_str-4);
        else
            RefCount()--;
    }
private:
    char*_str;
};

void test()
{
    String s1("hello world");
    String s2(s1);
}
int main()
{
    test();
    return 0;
}

当RefCount为1时正式调用析构函数。
当使用写时拷贝时,相比较深拷贝,减少了内存开销,优化了浅拷贝。

猜你喜欢

转载自blog.csdn.net/qqkb1016/article/details/79883737