Bugs I Often Write in C++

Every time I try to code a project in C++ I run into the same bugs, and I keep forgetting how to solve them. So, I decided to write this list here for my own reference.

Eigen initialization bug

Symptoms: The code compiles and runs properly, but the output seems random and changes from one run to the next, despite the code being theoretically deterministic.

Diagnosis: This happens because you am declaring a variable and calling it without initializing it. For example, Eigen::Matrix<int,3,5> A; will not create a matrix A of zeros, instead it will fill with entries with garbage from the computer’s memory.

Treatment: Go variable by variable and ensure that it is being properly initialized after being declared. For example, instead of Eigen::Matrix<int,3,5> A;, write

Eigen::Matrix<int,3,5> A;
A.setZero();

Linker error

Symptoms: The code seems to compile well but breaks just at the end of the compilation process, returning an error like ld: symbol(s) not found for architecture x86_64.

Diagnosis: This happens because you are not compiling one of the source files you’re using. For example, you wrote main.cpp which itself includes another function you wrote in func.cpp,func.h, but you are only compiling main and not func.

Treatment: If you are using CMake (and func is in a path that CMake checks for source code, e.g., include/ or /src if you are using CMake best practices), remove all CMake cache and build the project again,

rm -rf build
mkdir build
cd build
cmake ../

If you are not using CMake (even though you should) and instead compiling by calling your compiler directly from the terminal like gcc main.cpp -o main, then add func.cpp to the source files being compiled by calling instead gcc main.cpp func.cpp -o main.

Multiple inclusions

Symptoms: Compiling fails with errors like error: redefinition of ... or ... included multiple times.

Diagnosis: This happens because, when compiling, the compiler is reaching the same function or variable definition many times. For example, say we have a function main.cpp:

#include "func.h"
#include "func2.h"
int main(int argc, char *argv[])
{
    func(0);
    func2(0);
}

which calls functions func.cpp

#include "func.h"
void func(int a){ std::cout << a << std::endl; }

with header file func.h:

void func(int a)

and func2.cpp

#include "func2.h"
void func2(int a){ func(a+1); }

with header file func2.h:

#include "func.h"
void func2(int a)

When the compiler sees an include statement, it will literally just copy that file at that position in the code; and, of course, this works recursively. Therefore, since main is including func.h and func2.h, which in turn also includes func.h, when the compiler starts reading main.cpp and sees

#include "func.h"
#include "func2.h"

it will interpret it as

void func(int a)
#include "func2.h"

and then

void func(int a)
#include "func.h"
void func2(int a)

which recursively turns into

void func(int a)
void func(int a)
void func2(int a)

Thus, even without knowing it, we were defining the same function twice to the compiler’s eyes, and that makes it crash.

Treatment: The best way to be protected against this is always using include guards, a smart trick to ensure that the compiler will only enter the main text of each header file once. Basically, envelop every header file you ever write in an if statement like this:

#ifndef UNIQUE_NAME
#define UNIQUE_NAME

// header code here

#endif

Make sure that UNIQUE_NAME is unique for each header file and it never shares a name with any file or variable or functions ever read by the compiler. For example, you can make them all caps and make sure you never write all caps variable or function names.

So, in our example, we would make func.h

#ifndef FUNC
#define FUNC
void func(int a)
#endif

and func2.h

#ifndef FUNC2
#define FUNC2
#include "func.h"
void func2(int a)
#endif

By doing this, we avoid the compiler entering the same code twice and we avoid the error

Apple SDK mismatch

Symptoms: The code compiles successfully, but when ran returns an error that references the Apple command line tools, like:

/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSString.h:402:114: error: function does not return string type
- (nullable instancetype)initWithCString:(const char *)nullTerminatedCString encoding:(NSStringEncoding)encoding NS_FORMAT_ARGUMENT(1);
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                     ^                  ~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:103:48: note: expanded from macro 'NS_FORMAT_ARGUMENT'
        #define NS_FORMAT_ARGUMENT(A) __attribute__ ((format_arg(A)))

Diagnosis: This (I think!) happens because there is a mismatch between the versions of your operating system and the Apple Command Line Tools. This is caused by Apple itself sometimes (i.e., having the latest version of both does not necessarily solve this).

Treatment: I solve this by specifying a different compiler, by adding

set(CMAKE_CXX_COMPILER "/usr/bin/g++")
set(CMAKE_C_COMPILER "/usr/bin/gcc")

to my CMakeLists.txt. I am not really sure why this fixes this, but it does 🤷