C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
209: Practice Exercise: Building a Custom String Class
Why can't I just point to an existing C-string?
It's tempting to just store a char* that points to a string literal, but that's a recipe for a segmentation fault. If your class just holds a pointer to memory it doesn't "own," you have no way of knowing if that memory is still valid or if you're allowed to modify it. To build a real string class, you need to manage your own heap memory.
I usually start by allocating a buffer based on the length of the input string plus one for the null terminator. It looks something like this:
class MyString {
char* data;
size_t len;
public:
MyString(const char* str = "") {
len = std::strlen(str);
data = new char[len + 1]; // We own this memory now
std::strcpy(data, str);
}
~MyString() {
delete[] data; // Clean up or you've got a leak
}
};
I'm getting a crash when I pass my string to a function. What's happening?
You've probably hit the "shallow copy" trap. By default, C++ does a member-wise copy. If you have a MyString a = "Hello"; and then do MyString b = a;, both a.data and b.data are pointing to the exact same memory address. When the first one goes out of scope, its destructor calls delete[]. Then, when the second one tries to do the same, it's deleting memory that's already gone. Double free. Crash.
This is why you need a copy constructor and a copy assignment operator—the "Rule of Three." You have to explicitly tell C++ to allocate new memory and copy the actual characters over, not just the pointer.
// Copy Constructor
MyString(const MyString& other) {
len = other.len;
data = new char[len + 1];
std::strcpy(data, other.data);
}
// Copy Assignment Operator
MyString& operator=(const MyString& other) {
if (this == &other) return *this; // Don't delete yourself!
delete[] data; // Get rid of the old buffer
len = other.len;
data = new char[len + 1];
std::strcpy(data, other.data);
return *this;
}
How do I make the '+' operator actually work like a real string?
If you want to write str1 + str2, you can't just modify str1 in place; that would be a += operation. The + operator is expected to create a brand new string that is the combination of the two.
The trick here is to allocate a buffer large enough for both strings, join them using strcat (or a loop), and return a new MyString object by value. I personally prefer returning by value here because it's the most intuitive way for the user of your class to chain operations.
MyString operator+(const MyString& other) {
char* temp = new char[len + other.len + 1];
std::strcpy(temp, data);
std::strcat(temp, other.data);
MyString result(temp);
delete[] temp; // Clean up the temporary buffer
return result;
}📋 Practical Task
Exercise: Implementing the Memory-Safe String Buffer
Build a custom string class called SecureString that manages its own memory. Your implementation must satisfy the following requirements to ensure it doesn't leak memory or crash during assignments:
- Manual Memory Management: Use
new[]in the constructor anddelete[]in the destructor. - The Rule of Three: Implement a copy constructor and a copy assignment operator to prevent shallow copy crashes.
- Concatenation: Overload the
+operator to return a newSecureStringcontaining the combined text of two objects. - Access: Overload the
<<operator (friend function) so you can print yourSecureStringdirectly tostd::cout.
Test your class by creating a string, assigning it to another variable, and concatenating it with a third string to ensure no memory corruption occurs.
There are no comments for now.