The general meaning is to record the times of assignment through a tag, and decrement the tag in the structure. If the tag is 0, no object is sharing this memory, so you can call delete to release the memory.
#include<iostream>
#include<string>
#include<string.h>
#include<memory>
using namespace std;
class String{
public:
String(const char *str="");
String (const String &rhs);
String &operator=(const String &rhs);
~String();
const char &operator[](int index)const;
char &operator[](int index);
private:
struct StringValue{
int refCount;
bool shareable;
char *data;
StringValue(const char *initValue);
~StringValue();
};
StringValue *value;
};
String::StringValue::StringValue(const char *initValue):refCount(1),shareable(1){
data=new char[strlen(initValue)+1];
strcpy(data,initValue);
cout<<"StringValue constructor"<<endl;
}
String::StringValue::~StringValue(){
cout<<"StringValue destructor"<<endl;
delete[]data;
}
String::String(const char *str):value(new StringValue(str)){
cout<<"String constructor"<<endl;
}
String::String(const String&rhs){
if(rhs.value->shareable){
value=rhs.value;
cout<<"String copy constructor"<<endl;
++value->refCount;
}
else {
value=new StringValue(rhs.value->data);
}
}
String&String::operator=(const String &rhs){
if(value==rhs.value)
return *this;
if(--value->refCount==0)
delete value;
value=rhs.value;
++value->refCount;
return *this;
}
String::~String(){
if(--value->refCount==0){
delete value;
cout<<"String destructor"<<endl;
}
cout<<value->refCount<<endl;
}
const char &String::operator[](int index)const{
return value->data[index];
}
char &String::operator[](int index){
if(value->refCount>1){
value->refCount--;
value=new StringValue(value->data);
}
value->shareable=false;
return value->data[index];
}
int main(void){
{
String s=("string");
char *p=&s[0];
String s2=s;
*p='a';
cout<<s[0]<<" "<<s2[0];
}
return 0;
}
Note: there is a private nested class in String, which is used to assist in memory allocation and tag amount of String and whether the tag can be shared. Set to private so that only all members of the class use nested classes, which cannot be accessed externally.
Here I want to talk about the bool variable of shareable. In the absence of this value, the following code:
int main(void){
{
String s=("string");
String s2=s;
char *p=&s[0];
*p='a';
cout<<s[0]<<" "<<s2[0];
}
return 0;
}
If the definition of pointer p is in front of the definition of s2, both s and s2 will be changed by p. if p is in the back of s2, there will be no error. The reason is that the part of the operator [] of none const, as long as the tag is greater than 1, will generate a new one, so it will not affect s2. So use shareable to set whether it can be shared to limit this change.