fallout

This was a long week. We had E3 conferences starting Sunday night (for Brazil) and ending on Tuesday, with a lot of awesome – official – announcements: Fallout 4 (my next love), Dishonored 2, Doom 4 and new IPs such as Horizon (which looks very promising), unravel and others. During the week I’ve been playing Fallout shelter also announced on E3, which is a good-looking and funny mobile game, but has the same problems of other farming games: there is no end and it gets bored fast.

In the weekend, I start-and-finished The Last of Us. Man! What a game! I love post-apocalyptic games with adult narrative. My only regret is that I didn’t gave more time to it – I had to play on easy in order to finish in this weekend because I won’t be able to play it for the next week, and if I have more than 1 week gap between my gaming sections, I just can’t continue from where I stopped.

C++

Even with all stuff that happened this week, I almost finished the Accelerated C++ book. Here are some highlights:

Maps

You can create ordered maps defined in <map> and unordered maps defined in <unordered_map>. Their usage is similar, but map is slower to add new items due to the ordering function. Usage:

map<string, int> dict;
dict['key'] = 132;

If you try to access a nonexistent key in the map, this key will be created automatically.

Maps return pair objects as iterators. A pair type is defined as pair<const K, V> and has the following attributes (to key and value, respectively):

auto pair = dict.begin(); // first key in dict
pair->first // key
pair->second // value

About double angle brackets

In cases like map<string, vector<int>>, the compiler may have problem to parse the statement (due to the >> symbol), so it is recommended to use map<string, vector<int> > (with the space). This seems to be a an old practice, I doubt that compilers nowadays still have such problems.

Default arguments

You can use default arguments on function parameters, like Python:

void my_function(int non_default, int default=123) { ... }

Notice that, the parameters with default arguments must be the last items on the list.

Constant methods

C++ has a mechanism to protect object from write access, for example when you define a function like:

void my_function(map<K, V>& writable, const map<K, V>& non_writable) { ... }

where non_writable is constant. When a parameter is defined as constant, C++ only allows to read public attributes and call const methods, such as:

void my_function() const { ... }

Brackets on const maps

Due to the constant restriction described above, constant maps don’t have the operator [ ], because this operator changes the map when the key doesn’t exist.

Generics/Templates

Generics are called templates in C++ and is used as:

template <class T>
T my_function(vector<T> V) { ... }

With stand-alone functions you don’t have to specify the template explicitly, e.g.:

int a = my_function(my_int_vector);

The typename keyword

C++ has so many features on it that sometimes the compiler simply doesn’t know what to do. For instance, when you try to define a variable within a subtype defined inside a template, like this:

template <class T>
Class MyClass {
  T::SubType * ptr;
  ...
};

In this case, the compiler interprets SubType as a static member of T, thus, it tries to multiply SubType with ptr, causing an runtime error. Because of this, you always must use the typename keyword, avoiding compiler mis-interpretation:

template <class T>
Class MyClass {
  typename T::SubType * ptr;
  ...
};

Reference: http://stackoverflow.com/questions/1600936/officially-what-is-typename-for

Iterator categories

There are 5 types of iterators. They are divided by what they can do (thus, which operators are allowed) with the object they reference. The categories are:

  • Input
  • Output
  • Forward
  • Bidirectional
  • Random access

Consult http://www.cplusplus.com/reference/iterator/ to see the table of all operations these iterators handle

Stream iterators

istream and ostream can be used as iterators:

std::copy(v.begin(), v.end(), ostream_iterator<int>(std::cout));

This piece of code sends all elements of a vector v to the console output.

Default constructor

To avoid double initialization when you create an object, you must use the constructor initializers:

MyClass::MyClass():
  attribute1(0), attribute2(0) {
    ...
}

Without this, C++ initializes the object attributes before the constructor body, and in constructor you probably will initialize the attributes again.

Pointers

Just a reminder:

  • &x returns the address of the object x
  • *x returns the object in the address x

Pointers to functions

You can create pointers to functions as:

int (*fp) (int) = my_function

This creates a pointer fp of a function that receives and return int values. Notice that you don’t have to use &my_function, because C++ convert functions automatically. The same can be applied to the usage (you don’t have to call (*fp)(2), only fp(3)).

You can also return a pointer to function from another function, this is a bit tricky because you have to use typedef to declare the pointer before:

typedef int (*fp) (int);
fp my_function() { ... }

To return a pointer to a function that uses template is trickier, you will have to define a struct with the pointer and return the struct.

Arrays

C++ arrays are pointers to values and, thus, they can be used as iterators:

int array[] = {2, 3, 4, 5, 6};
int sum = std::accumulate(array, array+5, 0);

Notice that, the variable array stores only the first pointer, thus *a == 2.

The index usage array[3] is equivalent to say *(array+3).

Because array is only a bunch of pointers, you don’t have the type_size directly, but you can use size_t from <cstddef>.

File streams

Using input or output files is pretty easy:

ifstream infile("input.txt");
ofstream outfile("output.txt");

The usage is the same as cin and cout.

Specific streams

Instead of cout, you can use cerr for error output (it is preemptive, so it prints the string when it is called), and clog for logging (non-preemptive).

New and delete

To allocate and deallocate objects manually, use new and delete:

int *p = new int(42);
delete p

int *p = new int[3];
delete[] p

If you allocate an object manually, it will only be deallocate manually too. You must be very careful to avoid memory problems!

Explicit constructors

C++ allow explicit and implicit object initialization:

int p(4); // explicit
int p = 4; // implicit

The explicit keyword prevents the compiler to use the wrong constructor due to wrong type conversions:

class MyClass {
public:
    MyClass(int) {}
    explicit MyClass(double) {}
}

This

Another reminder: this is a pointer to the object.

Copy constructor

Passing an object by value to a function, returning an object by value from a function, or simply assigning one object to another variable, implicitly copies the object. The constructor used in the case is called copy constructor:

T::T(const T&)

Rule of the three

To control all creation and deletion process of a class, you must implement at least the following methods:

T::T() // and other constructors

T::~T() // destructor
T::T(const T&) // copy constructor
T::operator=(const T&) // assignment operator

Citing the book:

Because copy constructor, destructor, and assignment operator are so tightly coupled, the relationship among them has become known as the rule of three: If your class needs a destructor, it probably needs a copy constructor and an assignment operator too.

Read more