Our String Class
1#include <iostream> 2 3using std::cout; 4using std::cin; 5using std::endl; 6using std::ostream; 7 8class String { 9private: 10 size_t m_size; 11 char* m_buffer; 12 13public: 14 String(const char* string) { 15 m_size = strlen(string); 16 m_buffer = new char[m_size + 1]; 17 memcpy(m_buffer, string, m_size); 18 m_buffer[m_size] = 0; 19 } 20 ~String() { 21 delete[] m_buffer; 22 } 23 String(const String& other) 24 : m_size(other.m_size) 25 { 26 m_buffer = new char[m_size + 1]; 27 memcpy(m_buffer, other.m_buffer, m_size); 28 m_buffer[m_size] = 0; 29 } 30 31 char& operator[](int index) { 32 return m_buffer[index]; 33 } 34 35 friend ostream& operator<<(ostream& stream, const String& string); 36};
We also define our own <<
for printing our String
object.
ostream& operator<<(ostream& stream, const String& string) { stream << string.m_buffer; return stream; }
Why Copy Constructor is Always of this Signature? The Implicit Conversion
The function started at line 23, String(const String& other)
, is called the copy constructor of String
. In fact, when we do the assignment:
String name("James"); String name2 = name;
The second line undergoes the following processes:
- Compiler will determine whether
name
can be fed into one of the overloadings of our constructors. - If yes, it will do an implicit conversion and fed that parameter into that constructor, which is the copy constructor in our case.
Btw, anytime we see =
we are always copying something unless we are doing auto& a = b
, i.e., creating an alias.
Note that even a function returns a reference T& some_function()
doesn't mean auto a = some_function()
will store it as a reference, it keeps copying everything and create a
in the copy constructor.
Problem Without our own Copy Constructor
- By default the compiler will copy all the member variables, including the pointer
m_buffer
without copying the heap-allocated array. That's what we call shallow copy. - Exception will be caught when both
name
andname2
are our of the scope they live since~String()
will be called twice but bothname.m_buffer
andname2.m_buffer
point to the same heap-allocated array.
Test our String Class in main()
int main() { { String name("James"); cout << name << endl; String name2 = name; name2[3] = 's'; cout << name2 << endl; } cin.get(); }