(Not) detecting bugs

The following code contains a bug. A developer has spent quite some time looking for the source. The intent of this code is to iterate over two vectors simultaneously, from the first up to the one-before-last element. Thus the most interesting tools that will be employed will be boost::zip_iterator and std::prev.

#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <vector>

using zip_iter = boost::zip_iterator< 
int main()
  std::vector<int> v1 = {1, 2, 3, 4, 0};
  std::vector<int> v2 = {2, 3, 5, 7, 0};
  zip_iter beg {boost::make_tuple(v1.begin(), v2.begin())};
  zip_iter end {boost::make_tuple(v1.end(), v2.end())};
  auto process = [](zip_iter::reference){};
  std::for_each(beg, std::prev(end), process);

The purpose of a zip iterator is to iterate over a number of containers at the same time. It takes a tuple of iterators, each iterating over a different collection, and upon each dereference it returns a tuple of references: each reference to an element form the corresponding container.

I have simplified the program to the minimum. I am using GCC 5.3. This code compiles fine, but when I run it, it goes on and on. In this post we will see where the bug is, but more importantly, we will look at why this bug has not been detected during the compilation, and wasted a fair deal of the developer’s time. Continue reading

Posted in programming | Tagged , , , , | 3 Comments

More const — fewer bugs

I have just read article “Please declare your variables as const” by Bartłomiej Filipek. It argues that declaring your variables const is beneficial for reasons other than performance. In particular, it can help find bugs in your code. Now, let me illustrate this claim by showing how the const could help find the bug from my previous post. Continue reading

Posted in programming | Tagged , , | 10 Comments

Concealing bugs

Consider the following piece of program code.

void process_names()
  const char * fileName = "contents.txt";
  const char * foundName = 0; // will be assigned to later
  Names names = parse_file(foundName);
  foundName = find(names);
  // ...

This program is expected to open file contents.txt, read names from it; then find a desired name, and do something with it.

But the program will not do it, because I have a bug in this code. Accidentally, I have passed the wrong pointer to function parse_file: a null pointer. I confused them because names were so similar (I didn’t notice that my IDE suggested the wrong name in the hint); the types happened to match…

Now, would you like that this sort of bugs were detected at compile time? The correct answer is “yes”, but is it at all possible? Continue reading

Posted in programming | Tagged , , , , | 21 Comments

The One-Definition Rule

We have been hit by the same bug twice already this year. It ends in a crash, and it took developers days to find it (in each case), even though it is reproducible on each run of unit tests. The code, after significant simplifications, looks like this:

namespace tests
  struct Fixture
    std::vector<int> v1;
    std::vector<int> v2;

    static Fixture create();

    auto fixture = Fixture::create();
    std::cout << "running test1";

We are using a unit-testing framework that uses certain clever techniques, so that by only declaring the test, we are also registering it for being run. With this, anything related to testing one piece of functionality is neatly confined to a single file.

The problem is really not with macros. They basically expand to quite a simple construct, where the test is executed during the initialization of a global object. After further simplifications, the code looks like this.

namespace tests
  struct Fixture
    std::vector<int> v1;
    std::vector<int> v2;

    static Fixture create();

  // expanded from macro TEST_CASE(test1)
  struct UTF_test1_runner
    UTF_test1_runner();               // test run here

  UTF_test1_runner UTF_run_test1 {};  // init of a global

    auto fixture = Fixture::create(); // test contents
    std::cout << "running test1" << std::endl;

After the test contents have been run, the program crashes when the destructor of fixture is in progress. Can you see why?

Continue reading

Posted in programming | Tagged , , | 14 Comments

Concepts Lite vs enable_if

This post contains quite advanced material. I assume you are already familiar with Concepts Lite. For an overview of what Concepts Lite is, I recommend this proposal. Also, I have found this blog very useful regarding the details of and issues with concepts’ mechanics. One could look at Concepts Lite as three features:

  1. A superior alternative to enable_if (or overload hiding).
  2. The subsumption relation that enables the additional control of partial ordering in the overload resolution process.
  3. A convenient tool for building compile-time predicates that check for valid types and expressions.

In this post I will only focus on the first feature, and try to answer the question, “what do we need Concepts Lite for, given that we already have std::enable_if (and SFINAE)?” Continue reading

Posted in programming | Tagged , , , | 9 Comments

Is constructible?

Today I want to share with you something that really surprised me. Currently, Tomasz Kamiński and Ville Voutilainen are working on fixing a certain issue with std::optional’s converting constructors (which deserves a separate post). At some point, in the solution, they perform the following type-trait test:

is_constructible<T, U>::value || is_convertible<U, T>::value

If the varying order of T and U upsets you, rest assured that this is correct. This is how these traits are defined: is_constructible takes the created type first, whereas is_convertible takes the converted-to type second. But what really struck me here is the apparent redundancy. When type U is convertible to T does it not imply that T is constructible from U? Or in other words, if the following copy-initialization works:

T v = u;

The following direct-initialization:

T v (u);

should also work? Well, this is C++. It turns out that such expectation is not necessarily correct. Continue reading

Posted in programming | Tagged , , | 12 Comments

The cost of std::initializer_list

C++ aims to be a language for people working close to metal. It offers abstractions that cost no (or minimum) run-time or memory overhead. If you require zero-overhead abstractions, std::initializer_list may not be a tool for you. Continue reading

Posted in programming | Tagged , | 21 Comments