Skip to content

My C++ Interview Questions

Introduction

Over the years, I’ve done my share (more, it has often seemed) of interviewing candidates for C++ programming posts. During this time I’ve zeroed in on a small subset of questions I ask candidates. These have no correct answers, do not refer to manhole covers, and require no maths ability to answer. They have, however, proved effective in deciding if the candidate actually has some knowledge of C++. I present them for your delectation.

“Tell me about the copy constructor”

This is my start-off question. If people look blank when I ask it (and depressingly, lots do), then I write out the signature of the constructor for them. If they still look blank, the interview terminates – this has saved me a lot of time over the years.

What I’m looking for here is someone that knows how important copying is in C++, where it takes place, and how it can be avoided. I’d expect a decent C++ programmer to be able to talk for around 15 minutes on this, with me asking subsidiary questions.

“What are your favourite C++ books? And why are they your favourites?”

C++ is a very complex language, and to learn it thoroughly you simply have to read several good books – internet resources will not be enough. I don’t particularly care which books the candidate talks about, providing there is more than one of them, and they can come up with some convincing reasons for liking them.

“Write a program to…”

I’m not a big fan of getting candidates to write code in interviews. Often, the problem they are asked to solve is too small to prove anything, and they are unfamiliar with the setup on your specific workstations, so you are really testing how quickly they can get to grips with a toolset. However, sometimes HR or senior management will insist on a coding test. If that’s the case, then I set this problem, or something very like it, which tests the candidate’s familiarity with the C++ Standard Library in several ways:

Write a program that can be called from a command line environment like this:

myprog.bible.txt

The file bible.txt, which is provided, contains the text of the King James Bible. Your program should read this file and output the 10 most frequently occurring words, together with their frequency,  ignoring any punctuation and character case. Use the style of coding, commenting etc. that you would for a large program.

As with the other questions here, I’m not particularly interested in the details of the solution, provided they show a knowledge of Standard Library classes like strings and maps, and that the program actually works.

“What do you think the three most important features of C++11 are?”

Or similar – if the candidate has professed a knowledge of a library like Boost, I might ask about that instead. Once again, I don’t particularly care what the candidate thinks are important, only that they can talk about them articulately and knowledgably.

“If you were interviewing me, what question would you ask me”

This one is down to a guy I worked with at the now defunct Lehman Brothers (thank you, Mr James). He interviewed me, and after a couple of  questions said, “Well, you obviously know a lot more about C++ than I do, so tell me, if you were interviewing me, what questions would you ask?” I thought that was brilliant at the time, and still do – use it if you are interviewing a self-styled guru. Of course, you have to ask them why they would ask that question!

Conclusion

From the above, I think you can see that you do not have to ask candidates trick questions, or puzzles about manhole covers. Instead, you should be trying to get them to talk at length about their knowledge of the C++language and how it can and should be used.

Languages A-Z Challenge

I was futzing around with my CV today, and this question suddenly occurred to me:

Do I know a language for each letter of the alphabet?

And it turns out, no I don’t. here’s my best shot of an alphabetic  list of languages I do know reasonably well, and have been paid for writing programs in:

  • Awk
  • BASIC
  • COBOL
  • dBase II
  • E??????
  • FORTH
  • Gupta SQLWindows
  • H??????
  • IBM JCL
  • Java
  • K??????
  • Lahey FORTRAN
  • MASM
  • Nomad/2
  • Object Pascal
  • PHP
  • Quick C
  • Rexx
  • SeaChange
  • Transact SQL
  • U??????
  • Visual C++
  • W??????
  • X??????
  • Yacc
  • Z80 Assembler

The ?????? entries are ones I can’t provide.

Obviously, I know more languages than are listed here (many beginning with the letter C). The challenge I lay down is to produce a 26-element list of languages  given these rules:

  • You must have been paid for writing code in the language. For example, I have programmed in Haskell (which would give me the H entry), but nobody has ever paid me to do so.
  • You can use specific implementation names (like Visual C++), but a language (C++)  must be appear  only once in the list.

A small no-prize of  golden NULL pointer will be awarded for anyone that convincingly comes up with a 26 element list!

Less Than Obvious

Introduction

I was trying to revive some old C++ code at the weekend when I noticed a strange problem. I was using a std::set of objects of a class I’d created, I added objects to the set, but when I came to iterate through them a bit later, half of the objects seemed to have disappeared! What the heck could be going on? It took me quite while to realise what my problem was, because it was not at all obvious. This article describes the problem you may encounter when using ordered associative containers like std::set and std::map in your own code, but is not intended to be a complete guide to using these containers, or to sorting in general. You will need a little (but not much) C++11 knowledge in order to follow it. 

std::set 101

The std::set container class is part of the C++ Standard Library and implements a collection of unique key values which are maintained in sorted order. The std::map container is very similar, but associates a value with each key. You can use std::set like this:

#include <set>
#include <iostream>
using namespace std;

int main() {
    std::set <int> s;
    s.insert( 7 );
    s.insert( 2 );
    s.insert( 5 );
    for ( auto i : s ) {
        cout << i << endl;
    }
}

The for/auto stuff is C++11 syntax for iterating over the set,  which prints out:

2
5
7

If I added another insert statement:

s.insert( 2 );

then the insert would not take place, as the set already contains the value 2.

Sets are implemented internally as balanced binary search trees. If you have ever played with BSTs, you will know that you need to compare the value at each node with the thing you want to add to the tree in order to find the correct insertion place. For C++ sets, this comparison is performed by the Standard Library functor std::less, which itself uses the < (less-than) operator for the types in the set. This is fine and dandy if the things in the set actually have a less-than operator (as integers do in the case above), but what if they don’t?

A Point Struct

For the remainder of the article, I’ll look at the problems of creating a Point structure that you can store in a std::set. The Point structure implements a par of integer (x,y) coordinates, and a first attempt looks like this:

#include <iostream>
#include <set>
using namespace std;

struct Point {
    int x, y;
};

ostream & operator << ( ostream & os, const Point & p ) {
    return os << p.x << "," << p.y;
}

int main() {
    Point p1{1,2};
    Point p2{4,1};
    cout << p1 << " " << p2 << endl;
}

I’ve added a streaming output operator<<() for convenience. The braces around the values used to initialise the Point objects are part of C++11 uniform initialisation.

This code produces the output:

1,2 4,1

So far so good. But what happens if we try to create a std:;set of Point objects and to add the point p1 to the set:

int main() {
    Point p1{1,2};
    Point p2{4,1};

    set <Point> s;
    s.insert( p1 );
}

Well, if you try to compile that, your compiler will complain – in the case of my GCC compiler, it complains bitterly, producing one of those wall-of-text sequence of error messages we all know and love. The relevant message here is this one, which I’ve edited slightly:

required from here stl_function.h:235:20: 
error: no match for 'operator<' (operand types are 'const Point' and 'const Point')
  { return __x < __y; }

You can see that some code in the Standard Library implementation header stl_function.h wants to use the less-than operator on a couple of Point objects, but the compiler cannot find such an operator because we have not written one, and one is not provided by C++ by default. If we want to put Point objects in a set, we have to provide a less-than operator.

A less-than Operator

How to go about writing a less-than operator for our Point struct? There are actually several ways of going about doing this, but I am going to suggest that it should be implemented as a free, non-member function that takes two parameters. I don’t intend to go into the reasons for this here except to say that binary operators should generally be implemented as free functions, and that if you can avoid making something a member function, you probably should do so.  Our comparison operator in outline then should look like this:

bool operator < ( const Point & a, const Point & b ) {
    // what to put here?
}

What should the operator return? Put simply, it should return true if the parameter a is less than the parameter b. So your first thought might be to write something like this:

bool operator < ( const Point & a, const Point & b ) {
    return a.x < b.x && a.y < b.y;
}

and to test it like this:

int main() {
    set <Point> s = {{1,1},{1,2},{2,1},{2,2}};
    for ( auto p : s ) {
        cout << p << endl;
    }
}

This code compiles, as the compiler is now happy it has a less-than operator it can use, but unfortunately, when you run the program, you will get the following output:

1,1
2,2

where two of the Points seem to have disappeared! This was the problem I was having with my own code (though to be fair on myself, my code was considerably more complex than this Point structure). So, what is going on?

Strict Weak Ordering

The C++ Standard says that in order for a less-than operator to work correctly with sets and maps (and with some of the Standard Library algorithms), it must enforce what is known as "strict weak ordering". I don’t intend to go into any detail about exactly what this means here – if you want more details I suggest taking a look at this Wikipedia article. Suffice it to say that the comparison operator we have provided does not enforce it, and is in fact rather obviously not a great way of ordering 2D points.

But if what we have written does not enforce strict weak ordering, how to go about writing one that does? Unfortunately, doing so is both somewhat unintuitive (at least for me – you might like to test your own intuition by correcting the above comparison function) and very, very easy to get wrong if you are not methodical about your implementation. I’m going to suggest two approaches – a mechanical, algorithmic one, and a possibly better one using other C++ facilities.

The Mechanical Method

The mechanical method is simple. For each pair of values in the two parameters referred to as a and b in the less-than operator above, write code like this:

if ( a.x < b.x ) 
    return true;
if ( b.x < a.x ) 
    return false;

and finish off by returning false. So, using this method, our comparison operator becomes:

bool operator < ( const Point & a, const Point & b ) {
    if ( a.x < b.x ) 
        return true;
    if ( b.x < a.x ) 
        return false;
    if ( a.y < b.y ) 
        return true;
    if ( b.y < a.y ) 
        return false;
    return false;
}

If we decided to make Point a 3D point, containing a z coordinate, we would just add the statements:

if ( a.z < b.z ) 
    return true;
if ( b.z < a.z ) 
    return false;

With the above changes in place, the test program now produces the correct output:

1,1
1,2
2,1
2,2

This method may seem long-winded, but it has two big advantages. First, it is hard to get it it wrong – you can write the comparison function almost without thinking. And second, it only uses the less-than operator on the types it is comparing – this is important, as many types will not implement the full gamut of comparisons.

Using C++ Features

If you want to avoid the semi-boilerplate code above, C++ offers several other possibilities for providing things that you can store in a set.

One possibility is not to create your own Point struct at all. C++ provides several data structures that work much like a point, and which implement a suitable less-than operator out of the box. The most obvious of these is std::pair:

#include <iostream>
#include <set>
#include <utility>
using namespace std;

int main() {
    set <pair<int,int>> s = {{1,1},{1,2},{2,1},{2,2}};
    for ( auto p : s ) {
        cout << p.first << "," << p.second << endl;
    }
}

If you wanted to retain the Point struct, you could use std::pair to implement your custom less-than operator:

bool operator < ( const Point & a, const Point & b ) {
    pair <int,int> pa{a.x,a.y};
    pair <int,int> pb{b.x,b.y};
    return pa < pb;
}

You can do similar things with std::vector, or in C++11 with std::tuple and the very handy std::tie function:

bool operator < ( const Point & a, const Point & b ) {
    return tie( a.x, a.y ) < tie( b.x, b.y );
}

The latter would be my personal preference, and its what I ended up using to solve my own problem with providing a less-than operator.

Summary

  • If you want to conveniently put objects in a  set or a map, they must provide a less-than operator.
  • The less-than operator must enforce strict weak ordering.
  • Providing strict weak orderingis easy for human programmers to get wrong.
  • Use C++ features like pairs and tuples to provide it.

Thinking Like A Programmer

Introduction

Yesterday, someone posted a question on how to "think like a programmer" on /r/learnprogramming, and I gave this sage advice:

All programming comes down to writing functions. Always think about how you could solve a problem by writing more functions.

While I believe this to be good advice, it made me wonder what my own thought processes really are when I set out to tackle a problem. So I picked on of the other problems on yesterday’s /r/learnprogramming, and studied my own cogitations while I solved it, which may be of interest to beginner programmers. The solution is in C, and should be understandable by anyone with a modicum of experience in this language.

The Problem

The problem is given an array of integers containing the values 1 and zero, find the index of the longest contiguous sequence of the value 1, and the length of that sequence. In other words, given the array:

int v[] = {0,1,1,0,0,0,1,1,1,0,1};

we should end up with the values 6 for the starting index, and 3 for the length.

My Thoughts

Hmm, well I’m going to need a function which takes an array of ints as its parameter, and as we are using C, I’d better pass the length of the array as a parameter too. What shall I call the function? Let’s call it longest for now, so it will look something like this:

longest( int a[], int alen );

And I’ve got to have it return two values? Bugger. I guess I could pass a couple of pointers as parameters to the function and have it return via them?  Nah, lets make a structure to hold the return values. Something like this:

typedef struct {
    int start, length
} Seq;

Now I can write the complete (if empty) function definition:

Seq longest( int a[], int alen ) {
}

Now I’ll flesh this out a little by actually creating a Seq and returning it. And I’ll write a little main() to call it too:

#include <stdio.h>

typedef struct {
  int start, length;
} Seq;

Seq longest( int a[], int alen ) {
  Seq seq = {0,0};
  return seq;
}

int main() {
  int v[] = {0,1,1,0,0,0,1,1,1,0,1};
  int vlen =  sizeof(v) / sizeof(int);
  Seq s = longest( v, vlen );
  printf( "%d %d\n", s.start, s.length );
}

Now I’ll just compile that … yay – it compiles, and run it, which gives me the expected output:

0 0

So now I have to think how to find the longest sequence. I know I’m going to have to walk over that array somehow, so lets write something to do that:

Seq longest( int a[], int alen ) {
  Seq seq = {0,0};
  int i = 0;
  while( i < alen ) {
    i++;
  }
  return seq;
}

And that compiles too – good! Now, at each position in the loop I would really like to know the length of the sequence of the value 1 starting at that position. I’m going to need another function – I’ll call it seqlen. What am I going to pass to it as parameters? Well, it will need the array (and that damned length!) and the current loop index. And the return value – easy; it should return the length of the sequence, or zero if there isn’t one. So it will look like this:

int seqlen( int a[], int alen, int i )

So, how is this going to work? I need to make sure I’m not looking past the end of the array. Then, so long as a[i] contains the value 1 I’m in a sequence of 1′s, so I need to keep looping until I’m not. Something like this:

int seqlen( int a[], int alen, int i ) {
  int n = 0;
  while( i < len && a[i] == 1 ) {
    n++;
    i++;
  }
  return n;
}

Which also compiles! Great. Now I need to use it in my other function.

The problem says that I need to return the index of the longest sequence and its length. This means I’ve got to call seqlen repeatedly, and update the longest and length fields of my Seq struct whenever I find a new longest sequence. So I need to add some code to my while-loop in longest:

while( i < alen ) {
  int sl = seqlen( a, alen, i );
  if ( sl > seq.length ) {
    seq.length = sl;
    seq.start = i;
  }
  i++;
}

And when I run it it gives me the expected output:

6 3

That’s great, but looking at the code I notice that I’m incrementing the loop index in seqlen but then throwing away that increment when the function returns. This means that I’m doing a lot more work than necessary, though I do get the right result. I think a bit about whether this matters, and come to the conclusion that for small problem sizes it doesn’t, but it might for very large ones. In any case, the fix is easy – I just change the increment statement in longest to this:

i += sl ? sl : 1;

which adds the length of the sequence I found, or 1 if there wasn’t one and I just need to skip over a 0 value.

That change worked as  expected, and completes the code, which can be found here.

Summary

OK, so what did my thought processes and programming practices pan out as?

  • The very first thing I did was to think of a function I could write; I didn’t start writing loops or anything like that
  • I used a struct to return multiple values from a function, rather than doing so via pointers.
  • I wrote some simple code which didn’t solve the problem, but did compile. I then started adding small chunks of code to this.
  • I then thought of writing another function to handle a subsidiary part of the problem. If the problem was bigger, I would have come up with yet more functions.
  • The functions I wrote were short – in fact about typical of the length of functions in my code for "real" applications.

So, I guess my advice on /r/programming wasn’t so bad after all!

Lazarus: Risen From The Grave?

Introduction

Like many programmers "of a certain age" (such as the divine Ms. Stob), I used to do a lot of work with Borland’s Delphi product. When this came out back in 1995, it trounced its main rival, Visual Basic, both in terms of ease-of-use and of performance. Unfortunately, criminal incompetence on the part of its various owners, and the departure of its chief architect to Microsoft (where he designed C#, among other products) has seen its market share dwindle to almost nothing in recent years, and its pricing structure hasn’t helped, in an era of free software.

However, Delphi has always had its fanatical adherents, and some of them have created an Open Source version of the product called Lazarus. Available for Windows, Linux and the Mac, Lazarus provides a complete IDE for developing GUI applications (and non-GUI ones, if the fancy takes you) using the Object Pascal programming language. In this article, I kick the tyres of Lazarus by writing a very small "hello world" application.

Hello World

I am renowned for my exquisite taste in GUI design, and here is the final result of my labours using Lazarus. The user enters their name, clicks on a button, and the app greets them. After 5 seconds, both the input and the greeting fields are cleared automatically.

laz-done

I’ll now show you how I created this magnificent application!

Launching Lazarus

When you start Lazarus (which is a very fast operation compared with the likes of Visual Studio), you will be presented with a default application project containing a single empty form:

laz-start

The GUI should be familiar to old Delphi users, and won’t hold many surprises for others. At the top, you have the menu and toolbar, together with a tabbed palette containing the numerous GUI and non-GU controls that Lazarus provides. To the left is the object inspector, which allows the properties of the controls to be changed. In the centre are the two windows for editing the code and the components of the form you are working on, and at the bottom is a window for compiler messages and the like. Lazarus is resolutely multi-window – there is no option to tile the IDE.

Changing Properties

The first thing I want to do is to change some of the properties of the form. I’m going to change its title, and give it a non-sizable border. To do that, I clicked on the form in the IDE and then started changing things in the Object Inspector. First the form’s title; notice that as the form is also a control it uses the name "Caption" for this property:

laz-title

Changing the border style uses a dropdown menu provided by the Object Inspector:

laz-border

I want a non-sizeable, dialog-style border, so I chose bsDialog.

Testing The Changes

One of the main advantages of an IDE is that it encourages the "make a small change and see if it worked" style of programming, which discourages bugs from creeping into the code. I now want to run the program to see if the changes I’ve made look good. To do that, I simply hit the Run button on the toolbar. It’s here that difference from Delphi becomes obvious – the compile and link times for the program are nowhere near as good as they would be for Delphi. It’s not exactly slow (certainly its faster than a C++ compile and link would be), but there is a definite pause. Anyway, the resulting form looks fine:

laz-form1

Adding Controls

Time now to add some controls to the form. You do this by dragging them from the palette below the IDE’s menu:

laz-palette

As well as the "standard" controls, such as buttons and text edits, Lazarus comes with a wide variety of other controls (about 200 in all) to provide facilities like data aware grids, standard dialogs etc. And it’s easy to create your own controls from scratch, or to modify existing ones using inheritance. I added a couple of labels, a text edit and a button to the form, and used the Object Inspector to give them more meaningful names than the defaults provided by Lazarus, and to change their captions where appropriate:

laz-controls

Lazarus provides numerous options for aligning controls, which I used to make the "Who are you?" prompt and the associated text edit line up vertically.

Adding An Event

Like all modern GUI builders, Lazarus is event driven. Nothing much happens until the user clicks on a control, or performs some other action, at which point one or more event will fire. Events are associated with particular controls, I want to add an "OnClick" event to the "Greet" button which will read the text the user entered and set the "Greeting" label accordingly. Events are added from the Object Inspector:

laz-onclick 

I double-clicked on OnClick, and Lazarus generated the following event handler for me:

laz-event1

The event handler, like all Lazarus code, is written in Object Pascal. This will never be my favourite language, but it’s pretty easy to understand, and easy to pick up if you have a background in languages such as C++, Java or C#. The code I added to the handler looks like this:

laz-event2

The editor has code completion, but only for looking up method names – it won’t complete half-completed names like "Greet" in this case.

With this even handler in place, I can click on the button and have the app say "Hello" to me. I now want to reset the user input and the greeting to be empty after 5 seconds have elapsed. To do this, I need to add a timer to the form.

Adding a Timer

Timers are  controls which you add to the form in the same way as buttone stc. but which have no visual representation at run-time. The timer control can be found in the "System" palette:

laz-syspal

I placed a timer on the form, and then changed its Enabled property to False, and its interval to 5000 milliseconds. Then I modified the button event handler:

lazevent3

So when the button is clicked, the timer is enabled and the countdown commences. I now need to provide an event handler on the timer to clear the label and text edit:

laz-event4

And with that, the application is pretty much complete. I made a couple of cosmetic changes, such as the greeting’s font, but that’s about it.

Other IDE Features

Lazarus is a reasonably full featured IDE; as well as the code and form editing, you get some refactoring support and an integrated debugger. I was quite interested to see how the debugger performed, as I’ve always found the one in Delphi itself rather poor. So I set a breakpoint in the timer event handler and ran the app again. It quickly becomes clear that the debugger is none other than gdb, which could be a good thing or a bad thing, depending on your feelings about gdb. Lazarus does quite a nice job of putting a windowed interface on top of it, but I suspect that gdb’s problems when been driven from a GUI will show through if I ever needed to do anything complex in the way of debugging.

Conclusion

Lazarus  makes a very good stab at being a free, open-source Delphi clone. There are some rough edges, and the compile/link times could be a bit better, but on the whole I was pretty impressed with it. People looking for a GUI builder that works cross-platform on Windows, Linux and the Mac should consider giving it a try.