DEV Community

Cover image for C++ Traps That Caught Me Off Guard — A Beginner's Log
elysianx
elysianx

Posted on

C++ Traps That Caught Me Off Guard — A Beginner's Log

Learning C++ has been a journey full of traps. Here are three I hit — hope they save you some debugging time.

🎣 Trap 1: new[] + delete(instead of delete[])

Wrong Code

 int* a = new int[3];

 // delete a; ❌ --> undefined
Enter fullscreen mode Exit fullscreen mode
class MyClass{
public:
    ~MyClass(){
        std::cout<<"delete successfully"<<std::endl;
    }
}
int main(){
    MyClass* mc = new MyClass[2];
    //delete mc;  ❌ -> only outputs one "delete successfully"

Enter fullscreen mode Exit fullscreen mode

What Happens

C++ standard clearly states that this is undefined behavior. Relying on it is extremely dangerous — different compilers, optimization levels, and platforms may behave completely differently.

new[] + delete only calls the destructor once, while delete[] calls it for every element in the array. Using delete instead of delete[] causes resource leaks for the remaining elements.

How to Fix

 int* a = new int[3];

 delete[] a;  -> 
Enter fullscreen mode Exit fullscreen mode
class MyClass{
public:
    ~MyClass(){
        std::cout<<"delete sucessfully"<<std::endl;
    }
};
int main(){
    MyClass* mc = new MyClass[2];
    delete[] mc; ->  outputs "delete successfully" twice
}
Enter fullscreen mode Exit fullscreen mode

🎣 Trap 2: cin + getline eating your input

Wrong Code

int age;
std::string name;

std::cout<<"Enter age: ";
std::cin>>age;

std::cout<<"Enter name: ";
std::getline(cin, name); // ❌ name ends up empty!

std::cout<<name<<std::endl;
Enter fullscreen mode Exit fullscreen mode

What Happens

cin leaves a newline character (\n) in the input buffer, and getline reads it immediately — so it stops before you even type anything.

Why

cin >> reads the value you type but leaves \n in the buffer. getline stops reading when it encounters \n, so it grabs that leftover newline and returns an empty string.

How to Fix

std::cin >> age;
cin.ignore();    // 👈 Eat the leftover newline
std::getline(cin, name);
Enter fullscreen mode Exit fullscreen mode

🎣 Trap 3: Copy constructor vs copy assignment

class FixArray{
    std::string name_;
    int* data_;
    size_t size_;
public:
    ~FixArray(){
        delete[] data_;
    }

    FixArray(const FixArray& other) : FixArray(other.size_, other.name_){
        std::copy(other.data_, other.data_ + size_, data_);
    }

    FixArray& operator=(const FixArray& other){
        if(this != &other){
            int* new_data = new int[other.size_];
            std::copy(other.data_, other.data_ + other.size_, new_data);
            delete[] data_;
            data_ = new_data;
            size_ = other.size_;
            name_ = other.name_;
        }
        return *this;
    } 
};
Enter fullscreen mode Exit fullscreen mode

Many beginners can't tell the difference between a copy constructor and a copy assignment. Actually, it's quite simple:

// Copy constructor: creating a new object from an existing one
FixArray fa(10, "example");
FixArray fb = fa;    // 👈 copy constructor called

// Copy assignment: assigning to an already-existing object
FixArray fc(5, "other");
fc = fa;            // 👈 copy assignment called
Enter fullscreen mode Exit fullscreen mode

Copy constructor — creates a brand new object as a copy of an existing one.

Copy assignment — replaces the contents of an already-existing object with another object's data.

The key difference: copy constructor builds something from nothing; copy assignment replaces something that already exists.

These are three traps I hit while learning C++. If you're a beginner too, I hope this saves you some debugging time. Have you encountered other tricky C++ traps? Share them below!

Top comments (1)

Collapse
 
merbayerp profile image
Mustafa ERBAY

Nice summary! One thing I’d add is that the biggest beginner trap today is often using new/delete at all. Modern C++ encourages RAII and smart pointers (std::unique_ptr, std::shared_ptr) or containers like std::vector, which eliminate many of these memory management pitfalls. Learning why delete[] matters is important—but learning when you don’t need manual memory management is even more valuable.