The C++ bugs I love. ❤

Ayush Verma
4 min readMay 6, 2021

--

A curated list of common C++ pitfalls that you should avoid learning about the hard way.

Photo by Bankim Desai on Unsplash

While C++ is my favourite programming language for reasons that range from complete control, low-level memory access and the underlying trust-the-programmer philosophy of the language design, these are the very same reasons that have given me bugs that I have lost my sleep over and cost me hundreds in codeforces’ negative delta. While these may look childish at first, when you are writing full-fledged code, these will be hard to isolate and will cost precious time that could otherwise be used in problem-solving and… well you get the point, these are important. As a beginner, I would have loved to get a heads up about these. Do try to answer these questions yourself first before moving on to the explanations. Happy reading

All inputs are given through STDIN input stream and all outputs are written to STDOUToutput stream

  • Shallow vs. deep copies
    Determine the output
STDOUT:
100
100

Modifying the value t.a[0] modifies the value r.a[0] automatically. This is an easy exploit of shallow vs. deep copies. By default, the assignment operator = copies only the statically allocated values. While the integer pointer a is statically allocated, the array it points to is dynamically allocated. The solution here is to create a copy constructor. While this is easy to isolate, it’s easier to miss in the heat of a problem-solving frenzy.

  • Varying string operation complexity
    what is the overall complexity of the following snippet

Statement 1 and 2 have a complexity of O(n) where n is the length of the original string while statement 3 has a complexity of O(1). std::string, under the hood, implements a vector<char>. When we do str + 'a' or 'a' + str C++ allocates new memory equivalent to the sum of sizes of str and 'a' then copies the entire string and the character you’re trying to concatenate into this new memory in the needed order, thus costing linear time. whereas str+='a’ simply doesstr.push_back('a') in the += operator’s implementation. classic operator overloading. Thus overall complexity would turn out to be O(n).

  • Integer rollover
    Determine the output.
STDOUT: 
Nay

In C++, functions like string::lenth(), vector::size() and such return a value of special size_t datatype. size_t is always unsigned since attributes like sizeand length cannot be negative. Thus when trying to comparejwhich is -1 with a.size(), j gets implicitly typecasted to size_t and rolls over to a really big number 18446744073709551615 thus giving the undesired result.

  • Double comparison
    Determine the output
STDOUT: 
Nay

As a general rule of thumb, never do double comparisons with the == operator. A little debugger inspection would reveal that value of a, b, c is 0.10000000000000001, 0.20000000000000001, 0.29999999999999999 which will obviously not evaluate a + b == c to logical true. The right way to go about doing double comparisons would be to check for error tolerances. E.g. the above conditional should be written as abs((a + b)-c) < 1e-9 where 1e-9 is the acceptable tolerance in the result.

  • Homogeneity in ternary operators
    Determine the output

The above code will result in a compilation error. C++ is a statically typed language, that is the data type of every variable and the return type of every expression must be known at compile-time itself. The ternary expression cannot return a char* and an int depending on runtime calculations. Thus a ternary operator’s return expressions should always be homogenous.

  • Stray newline character
    Determine the output based on STDIN inputs
STDIN:
2
Yay
Nay
STDOUT:
Yay

Saved the best one for the last. When our code is supposed to take two strings as input and print them as output, it prints only one. Normal cin delimits its inputs on whitespace and sends the contents of the input buffer(temporary storage area of data) when the return key(enter) is pressed; whereas getline() modifies cin such that it delimits on newline ('\n') character. This is useful when we want to input strings that contain whitespace. Our Enter key serves both purposes. Now, when we input, say an integer, through normal cin, contents that were typed before the enter key was pressed are passed on to our program. However, the '\n' character is left behind in our input buffer. Then, during the first while loop iteration, when our program runs the getline(cin, str) the first thing that is encountered is the leftover newline character and getline() thus sends everything that was before this character i.e. nothing. An empty string. After that, in the second iteration, it normally inputs the next string Jon and prints it out.
The solution to getting the desired result here is to use a cin.ignore() before getline(). This function ignores everything from the last input, in our case a stray newline, and our code runs as it should.

While the list is clearly not exhaustive, I hope it does provide hints as to what details you need to look out for when you encounter an erratic bug. I would love to hear your favourite bugs if you have any.

--

--

Ayush Verma
Ayush Verma

No responses yet