目录

CPP 写时拷贝

目录

自己手写一个string类,实现写时拷贝,这里记录下实现要点;

默认构造函数、拷贝构造函数、赋值运算符重载、析构函数 ===»> 引入计数机制,类似于 shared_ptr

写时拷贝实现策略:

先判断引用计数是否为1,如果为1,则可直接修改;

如果不为1,计数减1,然后深拷贝数据,为计数器新开一个空间并将其设为1;


什么时候发生写时拷贝?

涉及修改数据的操作时发生写时拷贝,如*和 [] 操作,因此需要重载解引用运算符和 [] 运算符;


默认构造函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private:
    char* data;
    size_t* refCount;

    // Helper function to perform deep copy
    void deepCopy(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
        refCount = new size_t(1);
    }

public:
    String(const char* str = "") {
        deepCopy(str);
    }

拷贝构造函数

1
2
3
4
 // Copy constructor
    String(const String& other) : data(other.data), refCount(other.refCount) {
        (*refCount)++;
    }

赋值运算符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Assignment operator
    String& operator=(const String& other) {
        if (this != &other) {
            (*refCount)--;
            if (*refCount == 0) {
                delete[] data;
                delete refCount;
            }
            data = other.data; 
            refCount = other.refCount;
            (*refCount)++;
        }
        return *this;
    }

析构函数

1
2
3
4
5
6
7
8
// Destructor
    ~String() {
        (*refCount)--;
        if (*refCount == 0) {
            delete[] data;
            delete refCount;
        }
    }

重载解引用

1
2
3
4
5
6
7
 // 重载解引用运算符
    char& operator*() {
        if((*refCount) == 1)
            return *data;
        (*refCount)--;
        deepCopy(data);
    }

重载[]运算符

1
2
3
4
5
6
7
8
 // 重载[]运算符
    char& operator[](int index){
        if((*refCount) == 1)
            return data[index];
        (*refCount)--;
        deepCopy(data);
        return data[index];
    }

整体代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#include <iostream>
#include <cstring>

class String {
private:
    char* data;
    size_t* refCount;

    // Helper function to perform deep copy
    void deepCopy(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
        refCount = new size_t(1);
    }

public:
    String(const char* str = "") {
        deepCopy(str);
    }

    // Copy constructor
    String(const String& other) : data(other.data), refCount(other.refCount) {
        (*refCount)++;
    }

    // Destructor
    ~String() {
        (*refCount)--;
        if (*refCount == 0) {
            delete[] data;
            delete refCount;
        }
    }

    // Assignment operator
    String& operator=(const String& other) {
        if (this != &other) {
            (*refCount)--;
            if (*refCount == 0) {
                delete[] data;
                delete refCount;
            }
            data = other.data; 
            refCount = other.refCount;
            (*refCount)++;
        }
        return *this;
    }

    // Accessor method
    const char* c_str() const {
        return data;
    }

    // Mutator method to modify data
    void modify(const char* str) {
        if (*refCount > 1) {
            (*refCount)--;
            deepCopy(str);
        } else {
            delete[] data;
            strcpy(data, str);
        }
    }

    // 重载解引用运算符
    char& operator*() {
        if((*refCount) == 1)
            return *data;
        (*refCount)--;
        deepCopy(data);
    }

    // 重载[]运算符
    char& operator[](int index){
        if((*refCount) == 1)
            return data[index];
        (*refCount)--;
        deepCopy(data);
        return data[index];
    }
};

int main() {
    String s1("Hello");
    String s2 = s1; // Copy constructor, shared data
    String s3 = s2; // Copy constructor, shared data

    std::cout << "s1: " << s1.c_str() << std::endl;
    std::cout << "s2: " << s2.c_str() << std::endl;
    std::cout << "s3: " << s3.c_str() << std::endl;

    //s1.modify("World"); // Modify s1's data
    s1[2] = 'A';

    std::cout << "After modifying s1:" << std::endl;
    std::cout << "s1: " << s1.c_str() << std::endl;
    std::cout << "s2: " << s2.c_str() << std::endl;
    std::cout << "s3: " << s3.c_str() << std::endl;

    return 0;
}