Weekly Log #1 – Motivation and C++

I started this blog intended to post my developments and things that I’ve been learning during my path towards game industry. But, in general, I’ve only been writing tutorials and releases notes. Tutorials are pretty hard to do, because I like to create examples, format, make images, revise, and give details about what I’m writing about, and releases notes are only published when I have a release to announce. Both demand time, which I don’t have much lately. In consequence, my posts now have about 1-month gaps among them, and this isn’t good.

Thus, in order to keep my initial plan and write more frequently, I’m creating a weekly log, starting with this one, so I can register and tell what I’m studying or developing.

C++

In this post I will only talk about C++, which I’ve been studying almost exclusively.

First thing to say is, I’m following the book Accelerated C++ by Andrew Koenig and Barbara Moo. The book is pretty good, but I wouldn’t recommend for a total beginner. In my opinion you should learn the basic on other languages before getting this book – and language.

I am learning C++ in depth because I want to have some experience on the AAA industry, so this is pretty much obligatory. I understand that C++ is a pretty powerful language, but damn, this language is complex as hell. Notice that I’m not talking about syntax or readability, I’m talking about the concepts behind every feature of C++. There is a lot of redundancy (you can solve problems in a dozen of different ways) which seems to be caused by the performance concern (generally there is a super – but complex – parsimonious solution).

During the course of this book (and the followings) I will share more my thought about the language. For now, I’m going to give some highlights of interesting stuff on the book:

Abstraction

The author’s give a pretty good definition of abstraction right on preface:

We define abstraction as selective ignorance – concentrating on the ideas that are relevant to the task at hand, and ignoring everything else

Containers and size_type

Most STL containers provide a size_type type, which defines the appropriate type to hold the number of elements of a given container. For example, to move through a string, you should use:

std::string text;
std::string::size_type i;
for (i=0; i<text.size(); i++) {
  // stuff here
}

instead of:

std::string text;
int i;
for (i=0; i<text.size(); i++) {
  // stuff here
}

The reasons of that is because the number of elements in the container may be bigger than what int (or unsigned int, etc..) can handle.

The & operator

The & denotes a reference to some variable.

MyType a;
MyType b = a; // copies a
MyType& b = c; // a is a reference to a

As a good practice, you should use const to tell programmer when your function does not have intention to change the parameter value. E.g.:

void my_function(type& i_want_to_change, const type& i_dont_want_to_change)

The istream objects

istreams have a failure state that is kept until cleared, thus, if you put a string on to this:

int a;
std::cin >> a;

you won’t be able to read anything until you clear the stream:

std::cin.clear();

lvalue

Non-const arguments can only receive lvalues  (can’t be anonymous):

void my_function(Type& param) { ... }
my_function(4) // error!
Type a;
my_function(a) // ok!

The same is valid for return values.

Header files

You must avoid the use of using inside the header files, because your never know how the source file will use the variables. Avoiding using you avoid unnecessary conflicts.

Also, you must always use the preprocessor directives:

#ifndef UNIQUE_IDENTIFIER
#define UNIQUE_IDENTIFIER
// code here
#endif

because compiler insert the header code into the source files that import the header. Without it, the definitions would repeat several times causing errors.

Inline functions

Inlines functions are cool, they only exists before compiling. The compiler copy the body of the inline function where it is called. Use this to avoid the overhead by function calls.

Built-in exceptions

Import <stdexcept> to use the default error classes:

  • logic_error
  • domain_error
  • invalid_argument
  • length_error
  • out_of_range
  • runtime_error
  • range_error
  • overflow_error
  • underflow_error

using:

try {
  throw logic_error("Message")
} catch (logic_error e) {
  e.what(); // returns the message
}

Vector limitations

Vectors are optimized for random access and pushing/removing items from the beginning or end. Other operations are slow. The reasons for that is that vector move all elements back or forward when you change items at middle of the container.

Note: for fast insertions or removing, use list. However, list items can only be accessed sequentially.

Iterators

Iterators are cool, and in general are implemented as pointers (but not true all the time). You can use the following iterators:

container::const_iterator
container::iterator
container::reverse_iterator
container::const_reverse_iterator

each one for a specific situation: const to handle const values, reverse to reversed loops, iterator for common loops. For instance, to move through a string you can do:

for (auto it = my_string.begin(); it != my_string.end(); it++) {
  std::cout << *it; // print each string char
}

Overloaded function as arguments

You must avoid using overloaded function as arguments to functions, because the compiler can have problems to decide which function to use. Instead you should use an auxiliary function.

Static variables

You can use static storage class specifier on local variables inside functions. A static variable is created the first time the function is called and reused in subsequent calls.

Using functions as arguments

To create functions that receive other functions as parameters:

void my_function(type other_function(type2 param)) { ... }

A final note: the STL has A LOT of interesting things, for instance, check the algorithm package.

Your email address will not be published. Required fields are marked *

*