★ The Big Three Functions: Copy Constructor, Copy Assignment Operator, Destructor
◇ String Class
#ifndef __MYSTRING__
#define __MYSTRING__
class String
{
}
String::function(...) ...
Global-function(...) ...
#endif

Copy s1 to s3 (where s3 appears for the first time), and copy s2 to s3 (where s3 has already appeared);
◇ The Big Three, Three Special Functions
Since characters are dynamically changing, using pointers is the most reasonable approach. Point to a location and then dynamically allocate memory size. Do not specify a size.

char* get_c_str() const
{
return m_data;
}
// Will not change the value of m_data, marked with const.
◇ Constructor and Destructor (ctor and dtor)
Strings will have a terminator. The length is unknown but there will be a terminator [C/C++]; one is a specified length without a terminator, which is generally in the form of an array.
inline
String::String(const char* cstr = 0)
{
if(cstr)
{
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else{
m_data = new char[1];
*m_data = '\0';
}
}
inline
String::~String()
{
delete[] m_data;
}

◇ Class with Pointer Members Must Have Copy Constructor and Copy Assignment Operator

Generally, when assigning, a and b should have the same content, but they should not point to the same memory. If a changes, b will change as well, meaning they actually point to the same memory, and b’s original memory will have a leak issue.
◇ Copy Constructor (copy ctor)
inline
String::String(const String& str) // The incoming str will not be modified, so use const
{
m_data = new char[strlen(str.m_data) + 1]; // Create space to store the original
strcpy(m_data, str.m_data); // Copy the original one by one into the new space.
}
{
String s1("hello ");
String s2(s1);
s2 = s1;
}
◇ Copy Assignment Operator (copy assignment operator)
inline
String& String::operator=(const String & str)
{
if(this == &str)
return *this; // Check for self-assignment
delete[] m_data; // this is a, str is b
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
{
String s1("hello ");
String s2(s1);
s2 = s1;
}
Both a and b originally have content, a = b requires releasing what a originally had. Then create space as large as b, and assign b to a.
◇ Always Check for Self Assignment in operator=
★ Heap, Stack, and Memory Management
◇ Stack
A block of memory that exists within a certain scope. When you call a function, the function itself will create a stack to store the parameters it receives and the return address.
Any variable declared within the function body uses memory from the aforementioned stack.
◇ Heap
A global memory space provided by the operating system, dynamically allocated by the program, and must be manually released.
class Complex{...};
...
{
Complex c1(1, 2); // c1 comes from the stack
Complex* p = new Complex(3); // comes from the heap
}
When the scope ends, the space on the stack naturally disappears, while the space on the heap must be manually released.
◇ Lifecycle of Static Local Objects
class Complex{...};
...
{
static Complex c2(1, 2);
}
c2 is a static object, its lifetime persists after the scope ends, until the entire program ends.
◇ Lifecycle of Global Objects
Global objects
class Complex {...};
...
Complex c3(1, 2);
int main()
{
}
c3 is a global object, its lifetime also ends only after the entire program ends, and can be considered a static object whose scope is the entire program.
◇ Lifecycle of Heap Objects
class Complex{...};
...
{
}
◇ new: Allocate Memory First, Then Call Constructor
Complex* pc = new Complex(1, 2);

◇ delete: Call Destructor First, Then Release Memory
◇ Memory Blocks Allocated Dynamically in VC
The gray area is in debug mode
◇ Dynamically Allocated Arrays
Complex* p = new Complex[3]; // Create three complex numbers, forming an array String* p = new String[3];


◇ Array New Must Be Paired with Array Delete

★ Review of the Implementation Process of the String Class
class String
{
public:
String(const char* cstr = 0); // Constructor, initial value assignment
String(const String& str); // For functions, values change, so no need for const, but for single variables, they are unchanged, so const is needed.
String& operator = (const String& str);
~String();
char* get_c_str() {return m_data;}
private:
char* m_data;
}
Consider what kind of data is needed, the size of the data (generally, the length of the string is unknown, so use pointers and dynamically allocate memory later), a pointer is four bytes
Consider which functions need to be exposed for external calls
Specific implementation: place it outside the body
◇ Constructor and Destructor
◇ Copy Constructor (copy ctor) String::String(const String& str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data); // Constructor does not need a return type
}
◇ Copy Assignment Operator (copy assignment operator – is a member function)
From source to destination, the destination already has content
String& String::operator=(const String& str) // Member function has a return type
{
if(this == &str)
return *this;
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
Explanation of the & symbol: the object before it is a pointer, obtaining the address, while after the class it represents a reference.