c++ knowledge point----deep and shallow copy

More C++ knowledge points: C++ Directory Index


shallow copy

  • concept:

    Shallow copy, also known as bit copy, means that the source object and the copy object share an entity, but the referenced variables are different (names are different). Changes to either object will affect the other object.

  • Shallow copy problem

    1. When multiple objects share the same piece of memory, an object will be destructed after use, and other objects will use this space again, resulting in illegal access.

    2. Multiple objects must be destructed multiple times, but there is only one piece of memory, resulting in illegal destruction

  • Notice

    When in a custom class, no constructor is given and the assignment operator is overloaded, the general compiler will automatically synthesize it in the form of a shallow copy.

  • Shallow copy code

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

void Test()
{
    String s1("hello world");
    String s2=s1;
}

Draw a picture to explain this code:

write picture description here


deep copy

Deep copy means that the source object and the copied object are independent of each other, and changes to either object will not affect the other object.

Code 1: traditional writing


class  String
{
public:
    //构造
    String::String(const char* str )
    {
        if (str == NULL)
        {
            _str = new char[1];
            _str = '\0';

        }
        else
        {
            _str = new char[strlen(str) + 1];
            strcpy(_str, str);

        }
    }
    //拷贝构造
     //String s2(s1) 
    String::String(const String& s)
            :_str(new char[strlen(s._str)+1])
    {
        if (this != &s)
        {
            strcpy(_str, s._str);

        }
    }


    // s1 = s2 
    String& String::operator=(String s)
    {
        //1.将S2的字符串拷贝下来
        //2.释放原字符串s1空间
        //3.将临时字符串给s1

        if (this != &s)
        {
            char* tmp = new char[strlen(s._str) + 1];
            strcpy(tmp, s._str);
            delete[] _str;
            _str = NULL;

            _str = tmp;
        }

        return *this;

    }

    String::~String()
    {
        if (_str != NULL)
        {
            delete[] _str;
            _str = NULL;
        }
    }

private:

    char* _str;
    size_t _size;
    size_t _capacity;
};

Code 2: Modern writing

Draw a picture to explain the exchange pointer in modern writing

write picture description here


String::String(const char* str="")
        :_str(new char[strlen(str)+1])
{
        strcpy(_str, str);      
}

void String::Swap(String& s)
{
    swap(_str, s._str);

}
//拷贝构造
String::String(const String& s)
{
    if (this != &s)
    {
        String tmp(s._str);//构造临时对象,出了作用域自动析构
        Swap(tmp);//将指针进行交换
    }
}

//赋值运算符重载
String& String::operator=(String s)
{
    if (this != &s)
    {
        String tmp(s._str);
        Swap(tmp);
    }
    return *this;
}

copy-on-write + reference counting

Reference count:

In reference counting, each object is responsible for maintaining a count of all references to the object. The reference counter is incremented when a new reference points to the object, and decremented when a reference is removed. When the reference count reaches zero, the object will release the occupied resources.

Two reference counting methods:

Method 1: Re-open four bytes for reference counting

Method 2: Use a memory block for reference counting and strings, which is convenient for management

write picture description here

Code 1: Reference counting of method 1

//引用计数为另一块空间
引用计数为另一块空间
class String
{
public:
    void show()
    {
        cout << _str << endl;
    }


    //构造
    String(const char* str="")
        :_str(new char[strlen(str)+1])
        , _pCount(new size_t(1))
    {
        strcpy(_str, str);
    }

    //析构
    ~String()
    {
        if (--(*_pCount) == 0)
        {
            delete[] _str;
            delete _pCount;
            _str = NULL;
            _pCount = NULL;
        }
    }
    //拷贝构造
    String(const String& s)
        :_str(s._str)
        , _pCount(s._pCount)
    {
        ++(*_pCount);
    }

    //赋值运算符重载
    String& operator=(const String& s)
    {
        if (this != &s)
        {
            if (--(*_pCount) == 0)
            {
                delete[] _str;
                delete _pCount;
                _str = NULL;
                _pCount = NULL;
            }
            _str = s._str;
            _pCount = s._pCount;
            ++(*_pCount);
        }


        return *this;
    }

    //写时拷贝
    void CopyOnWrite()
    {
        if (*_pCount > 1)
        {
            char* newstr = new char[strlen(_str) + 1];
            strcpy(newstr, _str);
            _str = newstr;

            --(*_pCount);
            _pCount = new size_t(1);
        }
    }

    //可读可写
    char& operator[](size_t pos)
    {
        CopyOnWrite();
        return _str[pos];
    }
    //可读
    const char& operator[](size_t pos) const
    {
        return _str[pos];
    }



private:
    char* _str;
    size_t* _pCount;
};

Code 2: Copy-on-write of method 2

//引用计数在头上
class String
{
public:
    //构造
    String(char* str = "")
        :_str(new char[strlen(str)+5])
    {
        *((int*)(_str - 4)) = 1;
        strcpy(_str + 4, str);
    }

    //拷贝构造

        // s2(s1) 
    String(const String& s)
        :_str(s._str)
    {
        ++(*((int*)(_str - 4)));
    }


    //赋值运算符重载
    //s2 = s1 
    String& operator=(const String& s)
    {
        if (this != &s)
        {
            if (--(*((int*)(_str - 4))) == 0)
            {
                delete[](_str - 4);
            }

            _str = s._str;

            ++(*((int*)(_str - 4)));
        }
        return *this;
    }


    //析构
    ~String()
    {
        if (--(*((int*)(_str - 4))) == 0)
        {
            delete[](_str - 4);
        }
    }


    const char* c_str()
    {
        return _str;
    }


    void CopyOnWrite()
    {
        if ((*((int*)(_str - 4))) > 1)
        {
            char* newstr = new char[strlen(_str) + 5];
            newstr += 4;
            strcpy(newstr, _str);

            --(*((int*)(_str - 4)));
            _str = newstr;
            (*((int*)(_str - 4))) = 1;
        }
    }


    char& operator[](size_t pos)
    {
        CopyOnWrite();
        return _str[pos];
    }


    const char& operator[](size_t pos) const
    {
        return _str[pos];
    }



private:
    char* _str; // 引用计数在头上 
};

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325739110&siteId=291194637