C++98corebeginner
Copy Assignment Operator
C++98 · The Foundation · Compiler flag: -std=c++98
Explanation
An overloaded `operator=` that assigns one object's state to another existing object of the same type.
Real-World Scenario
Reassign a configuration object when settings change at runtime.
Quick Snippet
snippet.cpp
class Config { public: Config& operator=(const Config& other) { return *this; } };Full Example
copy_assignment.cpp
// CodeNebula - C++98 Example: Copy Assignment Operator
// Compile: g++ -std=c++98 -Wall -Wextra -o example copy_assignment.cpp
//
// This example demonstrates:
// - Overloading operator= for deep-copy assignment
// - Self-assignment check (critical for correctness)
// - The difference between copy construction and copy assignment
// - The "Rule of Three": if you need one of {copy ctor, operator=, destructor},
// you likely need all three
#include <iostream>
#include <cstring>
class String {
private:
char* data;
int length;
void cleanup() {
delete[] data;
data = NULL;
length = 0;
}
public:
// Default constructor
String() : data(NULL), length(0) {
std::cout << " [String] Default constructed (empty)" << std::endl;
}
// Parameterised constructor
String(const char* str) : data(NULL), length(0) {
if (str) {
length = std::strlen(str);
data = new char[length + 1];
std::strcpy(data, str);
}
std::cout << " [String] Constructed: \"" << (data ? data : "(null)")
<< "\"" << std::endl;
}
// Copy constructor (deep copy)
String(const String& other) : data(NULL), length(other.length) {
if (other.data) {
data = new char[length + 1];
std::strcpy(data, other.data);
}
std::cout << " [String] Copy constructed: \"" << (data ? data : "(null)")
<< "\"" << std::endl;
}
// ---- Copy assignment operator (deep copy) ----
String& operator=(const String& other) {
std::cout << " [String] operator= called" << std::endl;
// 1. Self-assignment check
if (this == &other) {
std::cout << " -> Self-assignment detected, skipping" << std::endl;
return *this;
}
// 2. Free existing resource
delete[] data;
// 3. Deep-copy from source
length = other.length;
if (other.data) {
data = new char[length + 1];
std::strcpy(data, other.data);
} else {
data = NULL;
}
std::cout << " -> Assigned: \"" << (data ? data : "(null)") << "\"" << std::endl;
// 4. Return *this to allow chaining: a = b = c;
return *this;
}
// Destructor
~String() {
std::cout << " [String] Destructor: \"" << (data ? data : "(null)")
<< "\"" << std::endl;
delete[] data;
}
// Utility
void print(const char* label) const {
std::cout << " " << label << " = \""
<< (data ? data : "(null)") << "\"" << std::endl;
}
void set(const char* str) {
delete[] data;
if (str) {
length = std::strlen(str);
data = new char[length + 1];
std::strcpy(data, str);
} else {
data = NULL;
length = 0;
}
}
};
int main() {
std::cout << "========================================" << std::endl;
std::cout << "1. COPY CONSTRUCTION vs COPY ASSIGNMENT" << std::endl;
std::cout << "========================================" << std::endl;
{
String a("Hello"); // parameterised ctor
String b(a); // copy CONSTRUCTOR (not assignment)
String c; // default ctor
c = a; // copy ASSIGNMENT (operator=)
a.print("a");
b.print("b");
c.print("c");
}
std::cout << "\n========================================" << std::endl;
std::cout << "2. SELF-ASSIGNMENT CHECK" << std::endl;
std::cout << "========================================" << std::endl;
{
String s("World");
s = s; // self-assignment -- must be safe!
s.print("s (after self-assign)");
}
std::cout << "\n========================================" << std::endl;
std::cout << "3. DEEP COPY VERIFICATION" << std::endl;
std::cout << "========================================" << std::endl;
{
String x("Original");
String y;
y = x; // deep copy via operator=
x.print("x before mutation");
y.print("y before mutation");
x.set("Modified-X");
x.print("x after mutation");
y.print("y after mutation");
std::cout << " (y is unchanged -- deep copy works!)" << std::endl;
}
std::cout << "\n========================================" << std::endl;
std::cout << "4. CHAINED ASSIGNMENT a = b = c" << std::endl;
std::cout << "========================================" << std::endl;
{
String a, b, c("Chain");
a = b = c; // works because operator= returns *this
a.print("a");
b.print("b");
c.print("c");
}
std::cout << "\n========================================" << std::endl;
std::cout << "5. RULE OF THREE SUMMARY" << std::endl;
std::cout << "========================================" << std::endl;
std::cout << " If your class manages a resource (heap memory, file handle, etc.)," << std::endl;
std::cout << " you should define ALL THREE:" << std::endl;
std::cout << " 1. Copy constructor - String(const String&)" << std::endl;
std::cout << " 2. Copy assignment - String& operator=(const String&)" << std::endl;
std::cout << " 3. Destructor - ~String()" << std::endl;
std::cout << " Omitting any one leads to shallow copies or resource leaks." << std::endl;
return 0;
}
// Expected output:
// ========================================
// 1. COPY CONSTRUCTION vs COPY ASSIGNMENT
// ========================================
// [String] Constructed: "Hello"
// [String] Copy constructed: "Hello"
// [String] Default constructed (empty)
// [String] operator= called
// -> Assigned: "Hello"
// a = "Hello"
// b = "Hello"
// c = "Hello"
// [String] Destructor: "Hello"
// [String] Destructor: "Hello"
// [String] Destructor: "Hello"
//
// ========================================
// 2. SELF-ASSIGNMENT CHECK
// ========================================
// [String] Constructed: "World"
// [String] operator= called
// -> Self-assignment detected, skipping
// s (after self-assign) = "World"
// [String] Destructor: "World"
//
// ========================================
// 3. DEEP COPY VERIFICATION
// ========================================
// [String] Constructed: "Original"
// [String] Default constructed (empty)
// [String] operator= called
// -> Assigned: "Original"
// x before mutation = "Original"
// y before mutation = "Original"
// x after mutation = "Modified-X"
// y after mutation = "Original"
// (y is unchanged -- deep copy works!)
// [String] Destructor: "Original"
// [String] Destructor: "Modified-X"
//
// ========================================
// 4. CHAINED ASSIGNMENT a = b = c
// ========================================
// [String] Default constructed (empty)
// [String] Default constructed (empty)
// [String] Constructed: "Chain"
// [String] operator= called
// -> Assigned: "Chain"
// [String] operator= called
// -> Assigned: "Chain"
// a = "Chain"
// b = "Chain"
// c = "Chain"
// ...destructors...
//
// ========================================
// 5. RULE OF THREE SUMMARY
// ========================================
// ...summary text...
Run command
g++ -std=c++98 -Wall -Wextra -o example copy_assignment.cpp