Overload[]
Version one
char&operator[](const int index)
{
assert(index>=0&&index<strlen(str));
return str[index];
}
const char&operator[](const int index)const
{
assert(index>=0&&index<strlen(str));
return str[index];
}
const char*c_str()const
{
return str;
}
int main()
{
String s1("yhpinghello");
char x=s1[1];
return 0;
}
Flexible array
For flexible arrays, it is not calculated in the size of the structure. The size of the
structure is 8 and the structure occupies 8 bytes, and the rest is for data
Overload [] version two
class String
{
struct StrNode
{
int len; // 字符串的长度
int size; // 记录柔性数组的大小;sizeof(StrNode)+len
//int ref; // 引用计数
atomic<int> ref;
char data[];// 柔性数组 存字符串
};
private:
StrNode* str;
public:
String(const char *s = nullptr) :str(nullptr)//构造函数
{
if (s != nullptr) // s = "tulun"
{
int len = strlen(s);
str = (StrNode*)malloc(sizeof(StrNode) + 2 * (len + 1));
if (str == nullptr) exit(EXIT_FAILURE);//申请空间失败
str->len = len;
str->size = 2 * (len + 1);//空间的大小,不算结构体,只记录柔性数组大小
str->ref = 1; //有对象指向字符串
strcpy_s(str->data, len + 1, s);
}
}
~String()//析构函数
{
if (str != nullptr && --str->ref == 0)
{
free(str);
}
str = nullptr;
}
}
Copy constructor
String(const String &s):str(s.str)//拷贝构造函数
{
if (str != nullptr)
{
str->ref += 1;
}
}
int main()
{
String s1("yhpinghello");
String s2(s1);
String s3(s1);
String s4(s1);
return 0;
}
The construction process is shown in the figure below. When
destructuring, ref–;
if s1 has been destructed, it cannot be used to construct s2 s3 s4
Overloaded assignment function
int main()
{
String s1("yhpinghello");
String s2(s1);
String s3("tulun");
String s4(s3);
s2 = s3;
return 0;
}
When s2=s3 is executed,
the str of s2 does not point to yhpinghello, the ref in the space of yhpinghello becomes 1, the str of s2 points to tulun, and the ref of this space of tulun becomes 3.
If s1=s3 is executed again
, the str of s1 points to tulun, The ref in the yhpinghello space becomes 0, and the ref in the tulun space becomes 4
String& operator=(const String& s)
{
if (this != &s)
{
if (this->str != nullptr && --this->str->ref == 0)
{
free(str);
}
str = s.str;
if (str != nullptr)
{
str->ref += 1;
}
}
return *this;
}
Look at the following code
String fun()
{
String tmp("yhping");
return tmp; // return String("yhping");
}
int main()
{
String s1("tulun");
String s2(s1);
String s3 = fun();
String s4;
s4 = fun();
return 0;
}
String(String&& s)
{
str = s.str;
s.str = nullptr;
}
String& operator=(String&& s)
{
if (this != &s)
{
if (this->str != nullptr && --this->str->ref == 0)
{
free(str);
}
str = s.str;
s.str = nullptr;
}
return *this;
}
Constructed with return String("yhping"); this way, the system is optimized, and the return construction object is directly s3 itself.
If you are constructing tmp, first construct the tmp object, and then assign tmp to construct s3, and move the construction in the
above two cases , How to overload +=?
Copy-on-write
Overload +=
If the tulun string is too long, you need to reapply. The
best way is as follows
String& operator+=(const String& s)
{
// s1 += s2;
//NULL NULL;
//NULL not
//not NULL;
//not not;
if (this->str == nullptr || s.str == nullptr)
{
this->str = s.str;
if (this->str != nullptr)
{
this->str->ref += 1;
}
}
else if (this->str != nullptr && this->str->ref == 1)
{
int dist = this->str->size - this->str->len - 1;
if (dist >= s.str->len)
{
strcat_s(this->str->data,this->str->size, s.str->data);
}
else//剩余空间拷贝不进去
{
str=(StrNode*)realloc(sizeof(StrNode)+sp->len + s.str->len + 1);
strcat_s(this->str->data,this->str->size, s.str->data);
}
}
else
{
StrNode* sp = this->str;
this->str->ref -= 1;
this->str = nullptr;
int total = sp->len + s.str->len + 1;//总的字节数
str = (StrNode*)malloc(sizeof(StrNode) + 2 * total);//开辟空间
str->len = total - 1;//字符串长度
str->size = 2 * total;//空间大小个数
str->ref = 1;
strcpy_s(str->data,str->size, sp->data);
strcat_s(str->data, str->size, s.str->data);
}
return *this;
}
Overload[]
int main()
{
String s1("yhpinghello");
String s2(s1);
String s3("tulun");
char x = s3[1];
x = s1[2];
s1[2] = 'W';
return 0;
}
const char& operator[](const int index) const//常方法,不改变
{
assert(str != nullptr && index >= 0 && index < str->len);
return str->data[index];
}
char& operator[](const int index)//普通方法
{
assert(str != nullptr && index >= 0 && index < str->len);
if (str->ref > 1)
{
str->ref -= 1;//断绝关系
StrNode* sp = str;
str = (StrNode*)malloc(sizeof(StrNode) + sp->size);
str->len = sp->len;
str->size = sp->size;
str->ref = 1;
strcpy_s(str->data, str->size, sp->data);
}
return str->data[index];
}
Typical copy
funA when writing, build sa, call the copy constructor, not empty, ref is 1, first take out 1, add 1 and then write in, but this 1 has been read out, add 1 to write When it entered, it was interrupted. Thread B came in, constructed the b object, entered, it is not empty, ref is taken out as 1, and after 1 is added, it is 2. When preparing for the follow-up, the 1 (dirty number) read before is added in , The last is 2, the competition relationship, resulting in three objects, ref=2, when the program exits, ref–,ref=0, causing the final program to fail How to change the
resource contention of threads
?
ref do not define integer
++a for execution, there are many lines of machine code
that may be interrupted by other statements.
How to solve
atomic operations (indivisible)
atomic<int> ref;
Can’t be done, and other threads can’t proceed