What is this weird colon-member (" : ") syntax in the constructor?

Viewed 125709

Recently I've seen an example like the following:

#include <iostream>

class Foo {
public:
  int bar;
  Foo(int num): bar(num) {};
};

int main(void) {
  std::cout << Foo(42).bar << std::endl;
  return 0;
}

What does this strange : bar(num) mean? It somehow seems to initialize the member variable but I've never seen this syntax before. It looks like a function/constructor call but for an int? Makes no sense for me. Perhaps someone could enlighten me. And, by the way, are there any other esoteric language features like this, you'll never find in an ordinary C++ book?

14 Answers

It's an initialization list for the constructor. Instead of default constructing x, y and z and then assigning them the values received in the parameters, those members will be initialized with those values right off the bat. This may not seem terribly useful for floats, but it can be quite a timesaver with custom classes that are expensive to construct.

Although this is an old discussion, I couldn't find any mention about delegating constructor, which uses the weird ":" symbol in the following way.

class Foo 
{
public: 
    Foo(char x, int y) 
    {}
    Foo(int y) : Foo('a', y) 
    {}
};

What it does is simply delegating Foo(y) into Foo('a', y) . So that

Foo foo(15); //=> foo('a', 15)

When defining a delegating constructor, you cannot have any members in initializer list besides targeted constructor.

What is the colon syntax (:) in the class constructor and what does passing an integer to a std::vector<> constructor do?

I'd like to explain the below example from this duplicate question:

class UnionFind {
    public:
        UnionFind(int sz) : root(sz) {
            for (int i = 0; i < sz; i++) {
                root[i] = i;
            }
        }
    private:
        vector<int> root;
    };
    
    
    int main() {
        
       
        UnionFind uf(10);
    }

The colon (:) signifies the start of an "initialization list", or "initializer list", which initializes each variable to the value in parenthesis. It is as though you were calling a constructor for each variable with that value in parenthesis being passed in to that variable's constructor.

So, : root(sz) initializes the root variable with an int sz, which is like doing vector<int> root(sz);. Doing it like this, however, allows sz to get passed in to the UnionFind class constructor.

Initializing a vector with a size like that is constructor #3 here (https://en.cppreference.com/w/cpp/container/vector/vector):

// Constructor (3) as shown at
// https://en.cppreference.com/w/cpp/container/vector/vector
explicit vector( size_type count,
                 const T& value = T(),
                 const Allocator& alloc = Allocator());

It constructs count (sz in the example above) number of elements into the vector, each with value T(), which means int() in this case since root is a vector<int>. int() looks like a function call but is basically an integer default constructor to value zero (0). It is called "value initialization". Think of it like calling an "integer constructor", if integers were objects and had constructors. See also my question here: What is a call to char() as a function in C++?

So, let's recap: : root(sz) in the constructor is like constructing vector<int> root(sz);, which creates sz number of elements in the root vector, each with initial value int(), which is the syntax for "value initialization" of an int to zero.

Note also that the count parameter passed to constructor #3 shown above really should be a size_type, which can be written as std::vector::size_type, and is usually size_t (see the "Member types" section here). So, it would be better to change int sz to size_t sz instead. Therefore, change this constructor line: UnionFind(int sz) : root(sz) { to this instead: UnionFind(size_t sz) : root(sz) {.

Related