Return to C++
Applying new experience to a language I haven't used in a long time

04 January 2015

When I was at university, I learned how to program in C++. I studied information engineering, which is a branch of electrical engineering that specializes in information systems (computers, programming and communication systems). I still think that for the market they were aiming for, C++ strikes a good middle ground in terms of learning how programming works. It teaches you some high level concepts, such as abstraction and object oriented thinking, which is useful if you need to work in a language like C# or Java later on. It also lets you get into low level details, like raw pointers and manual memory management, which are useful if you end up needing to program for a microprocessor in an assembly language.

Then, I graduated and got a job as a programmer. The first thing that you learn when you enter the working world is how little real world experience you get from university projects. As it worked out, I ended up working mostly in C# at first, with a smattering of HTML and JavaScript. Learning to use JavaScript properly and in a way that scales up had its own set of challenges. I learned a great deal about JavaScript when I did a single page web application project using AngularJS. Along with AngularJS, we brought in a bunch of tools to help the development process, including a JavaScript linter. Investigating the reasons for the errors taught me how little I actually knew about JavaScript.

I’ve been thinking that I’d like to work in C++ again for a while. Unfortunately, there’s a bit of a stigma around it where I work. The stigma isn’t too bad, but it basically comes down to the idea that you can’t be as productive in C++ as you can in a higher level language. There’s also the sentiment that if you need to do manual memory management you’re more likely to end up with leaky memory.

I’m not sure if these assumptions are really true, so as a learning exercise I’ve started working on a small C++ project in my spare time, and doing lots of reading on what tools and methodologies other people are using. The goal is to determine if it’s possible to be as productive in C++ as you can be in other languages, while maintaining a safety net from sneaky memory related errors, that would scale well to a small team of developers.

Compiling with CMake

The first tool that I’ve come to use is CMake. CMake is a tool for creating build scripts. So if you’re on a project with three developers, and they each have their own idea of which IDE is the best, then you define your build using one CMake file and it can generate a Makefile for the first developer and a Visual Studio project file for the other. So far, I’ve only been using it to generate a Makefile under Linux, so I might be making some fundamental mistakes that I’ll discover when I start trying to build on Windows.

CMake also allows you to add dependencies to third party libraries. You can even go as far as to have CMake download the third party library for you when you build.

Testing with GTest

There are many unit testing frameworks out there for C++, and as far as I can see they are very similar. I chose GTest.

I think that it’s important for a project of any size to have at least some framework for writing unit tests in place. It gives you a way to automate testing of features, and so decreases the chance of bugs getting into the final release.

Checking for Memory Issues with Valgrind

As I mentioned before, C++ is considered dangerous because there is a chance of running into memory management related problems. Valgrind is a dynamic analysis tool which can check your memory management at runtime. I have Valgrind watch while I run my unit tests.

If you insist that the developers on your team follow a test driven development approach, then you should have fairly good unit test coverage. If Valgrind is watching your unit tests cover the majority of your code base, then it should be able to pick up most memory related errors. Spectacular!

This has actually saved me once already. I misread a section of the Sqlite documentation and wrote myself a nasty memory management bug. Basically, I passed Sqlite a pointer to a string for a prepared statement, but the string went out of scope before Sqlite used it. The result was a program that appeared to work, but might have failed suddenly, unexpectedly, and catastrophically. Valgrind picked up the problem, and gave me a way to know when the bug was actually fixed.

If you can catch bugs like this when you’re just written them, then it’s actually fairly minor to debug and fix.

The best part of this is that the tools are automated, so you can run them on a continuous integration server. Have a policy in place that you’re not allowed to merge in code that isn’t covered by unit tests, and you’re not allowed to merge in code where Valgrind detects memory errors, and you should have a reasonable safety net in place in a team setting.

RAII (Resource Allocation is Initialization) and Smart Pointers

C++ can be used to write code that is remarkably safe in terms of memory issues, using a pattern called RAII. For me, this is one of the most important reasons to use C++ classes. Unfortunately, the name is rather clunky and non-descriptive.

Basically, here’s how the pattern works. You have some resource that your class needs to use. When you initialize your object, you allocate the resource. When your object goes out of scope, you free the resource. This is made possible by classes in C++ having not only a constructor, but also a destructor.

This is an example of a very simple program that one class, which owns a variable allocated on the heap.

example_class.h

class example_class
{
  private:
    int* ptr;

    //this class doesn't have a copy constructor or assignment operator
    example_class(const example_class& other);
    example_class& operator=(const example_class& other);

  public:
    example_class();
    ~example_class();
};

example_class.cpp

example_class::example_class()
{
  //constructor allocates ptr as an integer on the heap
  ptr = new int;
}

example_class::~example_class()
{
  //destructor frees the memory on the heap used by the class
  delete ptr;
}

main.cpp

int main()
{
  //an example_class is created on the stack.
  //It may reference objects on the heap.
  example_class obj; 

  //use obj here however you need to 

  return 0;
}
//function ends, and the function is popped off the stack
//obj's destructor is called automatically because it was declared on the
//stack, so it can free its resources
//the destructor will also be called if the function is aborted for any
//other reason, like an exception

It’s kind of like knowing that all classes are implicitly wrapped in a try/finally block that you can use to free resources.

Smart pointers get lip service here because they are a simple class intended present pointers in a more RAII friendly manner. So a smart pointer is a pointer that will have ‘delete’ called on it automatically when it goes out of scope, saving you from the dangers of memory leaks.

A word of warning, it is still possible to abuse memory while using this technique. For example, if in the example above you put obj on the heap instead of the stack, it wouldn’t be automatically cleaned up. It just makes things a bit easier to handle, and a bit cleaner.

Extend the Standard Library with Boost

As I mentioned earlier, CMake makes it easy to bring in third party libraries. I feel it’s necessary to give an honourable mention to Boost. It seems that every time I think “C# would have this built into the standard library”, I found what I was looking for in Boost.

As an example, I needed to be able to generate a unique identifier for objects. Boost has a set of UUID classes which worked great, including the ability to generate, serialize and deserialize the identifiers. I needed to do some basic logging, and found that Boost has a logging library. I think that having Boost in your project nicely fills in the more feature rich standard libraries you find in other programming languages, allowing you to be much more productive.

Takeaway

I think that it is indeed possible to become as productive in C++ as in any other language. This is only possible if you leverage tools and third party libraries, which are widely available. You also need your whole team to know C++ of course, but I don’t know of a language where you can just let people in who have never used it before without supervision.

I say that “I think” it is possible because I haven’t yet done enough C++ work to get myself to that level of productivity. I am hopeful to get there soon.

Disclaimer

Thinking that C++ is viable as a language to work in doesn’t mean it should always be used in every situation. I believe in using the right tool for the right job. If you want to add some simple scripting to a web page, you should probably be writing in JavaScript directly rather than compiling to it from C++. If you’re prototyping an algorithm that relies heavily on matrices, Octave/Matlab is probably a better choice. I merely mean that C++ should not be discounted immediately because of ideas that you have to do everything yourself and that manual memory management is dangerous.


If you liked this article, please share it on Twitter, Facebook, Google+, or by using the Permalink.


You can send me comments on this post at justin@worthe-it.co.za, or @JWorthe.


More on Worthe It

Previous Post

16 Dec 2014

Using Bitwise Operations in JavaScript for No Good Reason
Next Post

07 Mar 2015

A few examples of how to show that a panel is minimized
Latest Post

14 Aug 2017

A retrospective on a Rust audio signal processing program I wrote
Browse the Blog Archive

16 Dec 2014 - 14 Aug 2017

See all of the stuff I've written and put on this site.