1. Reference count
c + + reference counting can save memory and reduce the cost of building objects and destructors at the same time. The so-called reference counting simply means that each object shares an entity's data, but we need to realize the record of the object referenced to the data, so that the data can be safely deleted after the end of the last object reference.
Take the string as an example. Suppose we want to copy or assign the string, then the customer we want to present is their own independent string. As follows:
However, for the internal implementation of the computer, this way obviously has the phenomenon of redundant storage, so we expect the internal implementation of the computer to be like this.
In this way, the strings owned by all users are the same, but there will be a problem, that is, when one of the objects is destroyed, the data of other objects will not be accessible. Therefore, we need to count the references of the data, and only the last reference object can really destroy the data.
So the implementation is like this.
2. Copy on write
Although the above implementation counting method realizes reference counting, which can make multiple identical strings share the same data, when any one object modifies the data, the data owned by other objects will also change. Therefore, in order to avoid this situation, copy on write is adopted, That is, when an object wants to modify data, it will re assign a copy for modification, so that the object will have a new copy of data and will not share a copy of data with other objects.
If you are not satisfied with the statement, then it is possible.
String s1 = "Hello"; char *p = &s1[1]; String s2 = s1; *p = 'x';
The pointer p cannot be recorded by the counter, so this will cause the shared data to be modified.
In order to prevent the above situation, when a string tends to modify the shared data, set the data to the non shareable state, then in the above statement, s2 will not share the data with s1, but copy a new data.
The following is the implementation code with detailed comments:
//Reference count implementation string class My_string { public: My_string(const char* val = ""):value(new ref_count(val)) {} My_string(const My_string& other) { //If the data can be shared, it can be referenced directly, otherwise it will be reallocated if (other.value->isShareable) { value = other.value; ++(value->count); } else { value = new ref_count(other.value->data); } } My_string & operator=(const My_string & other) { //Check self assignment if (this->value == other.value) { return *this; } //If it is the last reference, delete the data if (-- value->count == 0) { delete this->value; } //If you can't share, you need to reallocate space if (other.value->isShareable) { value = other.value; ++value->count; } else { value = new ref_count(other.value->data); } return *this; } ~My_string() { if ( -- value->count == 0 ) { delete value; } } const char& operator[]( int val) const { return value->data[val]; } //Data may be modified, so copy on write strategy is adopted char & operator[](int val) { if (value->count == 1) {//If there is only one reference at present, there is no need to copy return value->data[val]; } --value->count; value = new ref_count(value->data); value->isShareable = false;//Cannot share in case char * P = &s [i] occurs in this way return value->data[val]; } private: //Set as a friend function so that private data can be accessed friend ostream& operator<< ( ostream & cout, const My_string& s); //Encapsulation of data struct ref_count { //String data char* data; //The shareable flag is set to false only when writing is possible bool isShareable; //Counter int count; //Constructor ref_count(const char * data_):count(1),isShareable(true){ data = new char[strlen(data_) + 1]; strcpy_s(data , strlen(data_) + 1 , data_); } //Destructor ~ref_count() { delete[] data; } }; //Each string has a pointer to the encapsulated data ref_count * value; }; // < < operator overloading ostream& operator<< (ostream& cout ,const My_string & s) { for (char* p = s.value->data; *p != '\0'; p++) { cout << *p; } return cout; }
The above codes refer to Article 29 of More Effective C + +.