This C++ Constructor Problem Will Drive 90% of People Crazy! (3 Fatal Pitfalls Hidden Too Deep)

What seems like a simple constructor hides countless dangers; how many can you avoid?

Recently, I came across a C++ constructor problem during a code review. It appears unremarkable but has caused many programmers to falter. Today, let’s uncover the 3 fatal traps of this “death constructor”!

Original code: Under the calm surface, dark currents surge

#include <iostream>#include <cstring>using namespace std;
class Student {private:    char* name;    int age;    double* scores;    int scoreCount;
public:    // Problematic constructor    Student(const char* n, int a, double* sc, int count) {        name = new char[strlen(n) + 1];        strcpy(name, n);        age = a;
        scores = new double[count];        for(int i = 0; i < count; i++) {            scores[i] = sc[i];        }        scoreCount = count;    }
    void display() {        cout << "Name: " << name << ", Age: " << age << endl;        cout << "Scores: ";        for(int i = 0; i < scoreCount; i++) {            cout << scores[i] << " ";        }        cout << endl;    }};

Does it look normal? Let’s uncover the traps step by step!

Trap 1: The Ghost of Memory Leak

Problem: The class has dynamic memory allocation but lacks a destructor!

// Missing destructor!// Every time a Student object is created, there will be a memory leak~Student() {    delete[] name;      // Correct: use delete[] for arrays    delete[] scores;    // Correct: use delete[] for arrays}

Fatal consequence: The longer the program runs, the more severe the memory leak becomes, ultimately leading to system crashes.

Trap 2: The Minefield of Shallow Copy

Problem: No custom copy constructor and assignment operator!

// Disaster strikes when copying!Student s1("Zhang San", 18, grades, 3);Student s2 = s1;  // Shallow copy! Both objects point to the same memory
// When s1 and s2 are destructed, the same memory will be deleted twice → Program crash!

Solution: Implement deep copy

// Copy constructorStudent(const Student& other) {    name = new char[strlen(other.name) + 1];    strcpy(name, other.name);    age = other.age;
    scoreCount = other.scoreCount;    scores = new double[scoreCount];    for(int i = 0; i < scoreCount; i++) {        scores[i] = other.scores[i];    }}
// Copy assignment operatorStudent& operator=(const Student& other) {    if(this != &other) {  // Prevent self-assignment        delete[] name;    // Release original resources        delete[] scores;
        name = new char[strlen(other.name) + 1];        strcpy(name, other.name);        age = other.age;
        scoreCount = other.scoreCount;        scores = new double[scoreCount];        for(int i = 0; i < scoreCount; i++) {            scores[i] = other.scores[i];        }    }    return *this;}

Trap 3: The Invisible Killer of Exception Safety

Problem: If new fails in the constructor, the allocated memory cannot be released!

Student(const char* n, int a, double* sc, int count) {    name = new char[strlen(n) + 1];      // May fail    strcpy(name, n);    age = a;
    scores = new double[count];          // If this fails, memory leak for name!    for(int i = 0; i < count; i++) {        scores[i] = sc[i];    }    scoreCount = count;}

Solution: Use smart pointers or exception-safe writing

// Method 1: Use smart pointers (C++11 and above)#include <memory>class Student {private:    std::unique_ptr<char[]> name;    std::unique_ptr<double[]> scores;    // ... other members;}
// Method 2: Traditional exception-safe writingStudent(const char* n, int a, double* sc, int count) {    char* tempName = nullptr;    double* tempScores = nullptr;
    try {        tempName = new char[strlen(n) + 1];        strcpy(tempName, n);
        tempScores = new double[count];        for(int i = 0; i < count; i++) {            tempScores[i] = sc[i];        }
        // Only assign to member variables if all allocations succeed        name = tempName;        scores = tempScores;        age = a;        scoreCount = count;
    } catch(...) {        delete[] tempName;    // Clean up temporary resources        delete[] tempScores;        throw;                // Rethrow exception    }}

Feel free to share your experiences with C++ object-oriented programming in the comments!

Leave a Comment