Best practices

You'll likely see some things in my examples that you either you don't understand or don't like. This section is dedicated to addressing why I make some of the choices I make.

As for style, I sometimes conform to Google's style guide, but don't always hit the mark.

Don't import the entire std namespace

When first learning C++, many tend to tack using namespace std; to the top of their code as a rule. This should be avoided.

The following example shows an ambiguity in resolving a function call because two namespaces have a function with the same name.

#include <iostream>

namespace foo {
  void print() {
    std::cout << "Hello from foo!" << std::endl;
  }
}

namespace bar {
  void print() {
    std::cout << "Hello from bar!" << std::endl;
  }
}

using namespace foo;
using namespace bar;

int main() {
  print(); // ambiguous - foo::print() or bar::print()?
  return 0;
}

This can be resolved by specifying which print to call - foo::print or bar::print.

If you find that writing foo::print repeatedly is too cumbersome, you can add using foo::print;, which will allow you to access print by name instead of foo::print. Typically when this is done, the scope of the using declaration is minimized. This can be seen in the following example:

#include <iostream>

int main() {
  using std::cout;     
  using std::endl;

  cout << "Hello, World!" << endl;
  return 0;
}

Personally, I think this looks clunky and would prefer to type a few extra characters than to minimize the scope and risk re-typing the entire using declaration again later, like in the following:

#include <iostream>

int main() {
  {
    using std::cout;
    using std::endl;

    cout << "Hello, World!" << endl;
  }

  {
    using std::cout;
    using std::endl;

    cout << "Hello, World (again)" << endl;
  }

  return 0;
}

Use initialization lists

There are two way to initialize members in C++:

The first is by assigning the variable in the body of the constructor:

class Foo {
  public:
    Foo() { bar = 42; } 
  private:
    int bar;
};

The other is by using initialization lists:

class Foo {
  public:
    Foo(): bar(42) {} // Call `int` constructor with value 42.
  private:
    int bar;
};

I prefer the latter for several reasons.

You won't need to have a large constructor body

This is completely a matter of opinion, but I think large constructor bodies are ugly. I'm of the opinion that constructors should have as little code as possible - initializing members and maybe calling an init method. By using an initialization list, the body will be much smaller. This makes the constructor much more readable and maintainable.

It's less efficient to use the assignment method

By using the assignment method, copies are constructed. Then when the assignment is made, the copy assignment operator is called to initialize the member. If the right-hand side of the assignment operator is expensive, making a copy is definitely not what you want. There's a way to circumvent this (i.e., prevent extra copies) that we will talk about later, but it's truly better to just use the initialization list as a rule.

Use std::size_t for sizes.

I'll often see something like the following:

int size = my_obj.size();

This is not good. Here's why:

The C++ Standard makes no guarantees about the size of int. In fact, it makes no guarantees about the size of any integral types.

It guarantees this:

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

It also guarantees that std::size_t is capable of expressing the size of any type in C++ lest it be ill-formed.

Because int is smaller than std::size_t, it will overflow faster if the size to be represented is too large.

If sizeof int is 4 bytes, it can address up to 32 bits: , which is the largest representable integer in a 32-bit system.

If my_obj.size() == 2147483647, there could be real trouble in the following example:

#include <iostream>

int main() {
  // Assume my_obj.size() == 2147483647
  int size = my_obj.size();
  size++;
  std::cout << size << std::endl;

  return 0;
}

We expect to see 2147483648, but instead we see -2147483648. This is because of integer overflow. This is undefined behavior in the C++ Standard, which is a huge no-no.

The moral of the story is that you should use std::size_t to express sizes. It's guaranteed to represent any size and it just makes sense.