Different people have different ideas of what is simple.

— Bjarne Stroustrup

Contents

Preprocessor

Tag brackets mean look for this file in the directory where all the standard libraries are stored.

#include <iostream>

Double quotes mean the same as tag brackets or the current directory if the specified file is found in it.

#include "main.hpp"

Namespace

The following line is an example of how kludgey C++ can be:

using namespace std;

I find this command to be awkward. It is cryptic, not part of your train of thought when trying to get something to work and, unfortunately, hardly ever unnecessary. This line simply must be included to activate the correct name space for certain important libraries. There may be others but <iostream> and <string> are definitely some that need this command.

Without it you need something like this.

std::cout<<"This is suboptimal.";

Although this is an annoying requirement because most of the time it is used mechanically in the case shown above, the namespace mechanism is a C++ feature that allows better organization and protection of program elements.

Comment Styling

In C, the comments are this bizarre syntax:

/* This is a classic C style comment. */

In C++ that is acceptable but there is another style that has a starting designator and runs to the end of the line. Like this:

// This is a C++ comment.
x++ // The beginning of this line is not a comment but this is.

Style

For style tips in general, you could do worse than to emulate these guys. (Do they not host it themselves anymore?)

Here’s another.

Variable Types

As with C, all variables must be explicitly declared before using. The point of this relates to C and C++ and their very explicit use of memory management.

Constants

Like C, make a variable immutable with the const keyword. Well, a "read-only variable", like the C++ error messages say, is an oxymoron.

This is simple in the simple cases. But there is all kinds of mischief that can arise from this. The most absurd to me is the mutable keyword which can make const declarations, uh, less const.

Type Details

Note
Actually in some situations the Cpp11 auto keyword (not to be confused with the K&R C auto compiler hinting) allows the types of variables to be automatically deduced from context. Some more information and examples.

bool Exclusive to C++!

Boolean

1byte

keywords true or false, or integers 1 or 0

char

Character or small integer.

1byte

signed: -128 to 127 unsigned: 0 to 255

short int (short)

Short Integer.

2bytes

signed: -32768 to 32767 unsigned: 0 to 65535

int

Integer.

4bytes

signed: -2147483648 to 2147483647 unsigned: 0 to 4294967295

long int (long)

Long integer.

4bytes

signed: -2147483648 to 2147483647 unsigned: 0 to 4294967295

float

Floating point number.

4bytes

+/- 3.4e +/- 38 (\~7 digits)

double

Double precision float

8bytes

+/- 1.7e +/- 308 (\~15 digits)

long double

Long double float.

8bytes

+/- 1.7e +/- 308 (\~15 digits)

wchar_t

Wide character.

2 / 4 bytes

1 wide character

Note that C++ is more strict about type casting that C.

Variable definitions in C generally must be at the beginning of a block whereas in C++ they can be anywhere in the block.

C++ provides a way to get a runtime check of what kind of type a variable is. This is done with the typedef function and is useful when variables can be any of several types or objects.

Enum

C enum values are always sized int whereas in C++ they are a distinct type and can have different sized values. This defines a new user type DOW.

enum DOW {Sun,Mon,Tue,Wed,Thu,Fri,Sat};

You can do a lot in the definition. Here the type declares a variable (casual) and sets it.

enum DOW {Sun,Mon,Tue,Wed,Thu,Fri,Sat} casual=Fri;

Some people believe that enums should be named as singular nouns and not plural. Although enums may define a collection of possibilities for ,say, problem_types, the possibility will just be a problem_type when actually used.

Implicit Conversions

  • integer to float = OK

  • char to float = OK

  • float to int = OK (truncated obviously)

  • float to char = silently does the wrong thing

Strings

Classic C Style - cstring

Because C++ is based on C, the spartan techniques of old school C work in C++ too. Note that as in C, double quotes signify strings and single quotes are characters.

#include <iostream>
using namespace std;
int main(){
    char my_char_array[4]= {'a', 'b', 'c','\0'};
    cout << my_char_array << endl;
    char unterminated_rubbish[3]= {'x', 'y', 'z'};
    cout << unterminated_rubbish << endl;
    char fixed_len_msg[]= "Really just an array of simple chars.";
    cout << fixed_len_msg << endl;
    return 0;
}

Note that in the example that unterminated_rubbish is just that. With no termination, functions like cout just keep reading memory until it finds a null. It can pick up all kinds of wacky stuff. In my example I found that it printed the abc string too until it found its termination byte.

abc
xyzabc
Really just an array of simple chars.

So think carefully about using this style of C character array strings with C++ functions. However the cstring library can be used with this kind of string and it does work fine if done carefully.

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    char fixed_len_msg[13]= "Ok C string.";
    char msg_copy[13];
    strcpy(msg_copy,fixed_len_msg);
    cout << fixed_len_msg << endl;
    cout << strlen(fixed_len_msg) << endl;
    cout << strcmp(msg_copy,fixed_len_msg) << endl;
    cout << msg_copy << endl;
    cout << strcat(msg_copy,fixed_len_msg) << endl;
    cout << strcmp(msg_copy,fixed_len_msg) << endl; // <0 if A<B, >0 if A>B
    cout << *strchr(msg_copy,'C') << endl; // returns ptr to pos of char 'C'.
    cout << *strstr(msg_copy,"Ok") << endl; // returns ptr to pos of string "Ok".
    printf("The length is: %04d\n",strlen(msg_copy));
    return 0;
}

That code produced this output.

Ok C string.
12
0
Ok C string.
Ok C string.Ok C string.
-28
C
O
The length is: 0024

string Class

In C++ the string class is a more elaborate mechanism for working with strings. Strings are generally used like this:

#include <iostream>
#include <string>
using namespace std;
int main(){
    string mystring("Defined in constructor.");
    string somedots(4,'.');
    cout << mystring << endl;
    mystring= "Redefined by assignment.";
    cout << mystring << somedots << endl;
    cout << somedots + "and concatenation." << endl;
    cout << mystring.size() << endl;
    return 0;
}

Produces this.

Defined in constructor.
Redefined by assignment.....
....and concatenation.
24

Note that because it is a class (string) it can be initialized like a new object as an initialization function parameter. Subsequent redefinitions use the overloaded = operator to simulate the way normal people would expect a programming language to work.

Methods for string class include:

  • S.length()

  • S.size()

  • S.empty() - 0 if not empty and a 1 (or maybe some other nonzero) when it is indeed empty.

  • S.append("suffix") - A lot like +.

  • S.assign()

  • S.replace()

  • S.find(str2,pos) - Find the first occurrence of an entire second string’s position within string S. The pos parameter is to start looking only after a certain position; 0 is search all.

  • S.rfind() - Like find but finding the last occurrence. And pos is the maximum character to search. A value greater than or equal to S.length() searches the whole thing.

  • S.find_first_of() - Searches a string S for any characters supplied. Position limits are like find().

  • S.find_last_of() - Same as find_first_of() but the like rfind().

  • S.find_first_not_of() - Invert the match checking of find_first_of.

  • S.find_last_not_of() - Inverted matching of find_last_of.

  • S.compare()

  • S.erase() - Erases particular characters specified by 1. position and length, 2. iterator position, or 3. starting and ending iterators.

  • S.push_back(char) - Append a character.

  • S.reserve()

  • S.substr()

For find operations, if the target is not found, it will return string::npos which on my system produced 18446744073709551615 (2^64-1). Checking the return value for this is how you check if something was found.

Input And Output

C uses scanf and printf for input and output. C++ can use these but idiomatic C++ programs use a different mechanism not available in C.

cin>>
cout<<

These are available from include #iostream. You probably also want to turn on using namespace std; to cut down on trivial scope chatter. These are really not exactly functions but more like named pipes (in the std namespace) which get data sent in and out of them (<< and >> are overloaded operators normally used for bit shifting).

The >> operator is the "extraction" operator and reads input "items" which are expected to be delimited by whitespace (space, newline, tab).

if (fileStream.is_open())
    while (fileStream.good()) {
        string word;
        fileStream >> word;
        // Do something with "word"
        }

Here is a complete output ("insertion" operator) example:

#include <string>
#include <iostream>
using namespace std;
int main () {
  string thestr("String objects can be output like so.");
  cout << thestr << endl;
  return 0;
}

The cout doesn’t just dump a \n; it also performs cout.flush().

Here are some good notes on C++ IO.

cin and getline

It seems that cin is good for reading space delimited fields one field at a time (or something like that), but it doesn’t read whole lines.

#include <iostream>
#include <string>
int main() {
    std::string myLine;
    std::cout<<"Enter the whole line: ";
    std::getline(std::cin, myLine);
    std::cout<<"Your line is: "<<myLine<<"\n";
    return 0;
}

Here is an example of reading each character of standard input into a string.

#include <iostream>
#include <string>
using namespace std;
int main () {
  string docstr;
  while (!cin.eof()) { docstr.push_back(cin.get()); }
  docstr.pop_back(); // Ditch the last thing read, the End Of File FF.
  cout << docstr;
  cout << docstr.length() << endl;
  return 0;
}

iomanip - Manipulators

Instead of old C stdio.h printf formatting, C++ prefers you to use something called a "manipulator". The classic endl is such a thing. For more complicated manipulations, you’ll need to use <iomanip>.

Depending on how wild you get you may want to preserve stream formatting settings before mucking them up and then restoring them when you’re done. To save a copy of the current settings, use something like this.

// Include these...
#include <iostream>
#include <iomanip>
// Save existing settings.
ios:fmtflags preserved_flags= cout.flags();
int preserved_precision= cout.precision();
// Do some crazy stuff.

// Restore settings with this.
cout.flags(preserved_flags);
cout.precision(preserved_precision);

To pad with leading zeros (or any character) use something like this.

cout << setfill('0') << setw(10) << mynum << endl;

Here is a lesson about manipulators.

#include <iostream>
#include <iomanip>
int main () {
    std::cout<<std::setw(15)<<"Padded 15"
             <<std::setw(20)<<"Padded 20"<<std::endl;
    return 0; }

Besides the normal setw, there is also setfill, setprecision, and setbase. In Cpp11 there are some manipulators for money and time. (See here.)

stringstream

#include <iostream>
#include <string>
#include <sstream>

int main () {
    std::string stringifiednumber;
    float mynumber = 0;
    std::cout << "Enter number: ";
    std::getline (std::cin,stringifiednumber);
    std::stringstream(stringifiednumber) >> mynumber;
    std::cout<<"Plus one would be: "<<++mynumber<<"\n";
    return 0;
}

File Operations

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(){
    string line;
    // Create output stream for writing in append mode.
    ofstream f2write ("input.txt", ios::app);
    if (f2write.is_open()) {
        f2write << "\nThe End.\n";
        f2write.close();
    }
    else
        cout << "Unable to open file for writing";
    // Create input stream for reading.
    ifstream f2read ("input.txt");
    // The file is opened at ifstream creation.
    if (f2read.is_open()) {
        while ( getline (f2read,line) ){ cout << line << '\n'; }
        f2read.close();
    }
    else
        cout << "Unable to open file for reading";
    return 0;
}

Memory

Some C++ specific keywords, new and delete, help with memory allocation and deallocation issues.

Functions

In C it is good practice to prototype functions (describe their input and output before using them).

Unlike C, in C++ functions can be overloaded. This means that their meaning can be redefined.

Also C++ can use functions inside of structures. This is not common but it hints at the more C++ way of organizing functionality, classes, discussed in the next section.

Unlike C, C++ allows the program to define default values for function arguments.

Increment Operators

Prefix operators (e.g. ++var) increment the value and then return a reference.

Postfix operators (e.g. var++) create a copy of the variable, increment the value, then return the copied, unincremented value.

Also C++ has += and other such operators as found in Python.

Inline Functions

C++ discourages the use of preprocessor complexity. Instead, the idiomatic C++ way to do preprocessor functions is with the keyword inline.

Control Flow

if-else
if (x>=y) {dothis();}
else if (x<y) {dothis();}
else {dothis();} // Optional.
case
int choice=1;
switch (choice) {
    case (0) : cout<<"no"<<endl;  break;
    case (1) : cout<<"yes"<<endl; break;
    default : cout<<"huh?"<<endl;
}
for
for (int i=0; i<10; i++) {
    std::cout<<i<<endl;
}
for with implicit type casting
#include <cstddef>
for (std::size_t i=0; i<10; i++) {

There is also a newish for more like Python or Bash.

for ( declaration : range ) statement;
while
while (conditional) { do_stuff(); // Keep it up! }
do { do_stuff(); } while (conditional); // Make sure at least one happens.

Both break, to exit the loop immediately, and continue, to conclude the current loop body execution and go on to the next, are valid.

To get an infinite loop that needs a break to get out of (or not) here are options.

for (;;){... }
while(1){... }

Pointers

int I=20, *pI;
pI= &I; // Pointer to I is the address location of I.
cout << *pI; // Dereference returning value pointed to by pI.

References

References are a feature specific to C++ not found in C. Although the subtleties get complex, the greatest utility of references is simply as a way to pass by reference to functions easier. You can still move things around by pointers if you want but references often allow function calls to be less complicated.

  • In Unix terms, I think of pointers as symlinks and references as hard links. The reference is the object accessed differently, not a pointer to an address that may not contain anything.

  • You can also think of a reference as a constant pointer.

  • Pointers are variables that contain memory addresses while references are additional definitions of compiler tracked objects. (The compiler thinks: "Ah, he’s calling x another thing, y, now too.") Of course the compiler can use the same machinery it uses for pointers for this but references can be implemented more efficiently. That’s up to the compiler.

  • References point to objects (whose address a reference shares), while pointers can point to other pointers, ad infinitum.

  • References can (should) not normally be NULL.

  • References can not iterate using pointer arithmetic.

  • Pointers need to be dereferenced with *, or -> for class members, while references can be dereferenced with . like the referent ("automatic indirection").

Simple Demonstration Of References
#include <iostream>
using namespace std;

// Function with reference parameters.
void one2theother(int &from, int &to) { from--; to++; }
// Function with reference parameters returning a reference.
int &add2together(int &a, int &b) {
    int s; int &r2s=s; r2s= a+b; return r2s; }

int main () {
    int var= 10; int var2= 99;
    int &ref2var= var;
    cout << var << endl      // 10
       << ref2var << endl;   // 10
    ref2var++;
    cout << var << endl      // 11
       << ref2var << endl;   // 11
    var++;
    cout << var << endl      // 12
       << ref2var << endl;   // 12
    one2theother(var,var2);  // Function using references.
    cout << var << endl      // 11
       << ref2var << endl    // 11
       << var2 << endl;      // 100
    cout << add2together(var,var2) << endl; // 111
    return 0;
}

Here is a lot of expertise on the topic for those who really need it.

Classes

C++ features organization by classes.

Table 1. Special Member Functions

Default constructor

X()

Destructor

~X()

Assignment operator

void operator=(X &src)

Copy constructor

X(X &src)

Printing function

void print(ostream *os)

Example of Using Classes
// cxe- Wed May 12 12:22:10 PDT 2004
// This is a test of using inheritance to create a containable class (or array
// in this example) of heterogenous objects. The goal will be to store 2
// classes in the same array in such a way that they are usable.

#include <string>
#include <iostream>
using namespace std;

class Number {  // This is the base class.
   public:
      Number() {}
      virtual void show() { cout << "No base class data!" << endl; }
   private:
}; // end class Number

class Roman: public Number {
   public:
      Roman operator=(string p) { pretium= p; return *this; }
      void show() { cout << "Roman:" << pretium << endl; }
   private:
      string pretium;
}; // end class Roman

class Arabic: public Number {
   public:
      Arabic operator=(int v) { value= v; return *this; }
      void show() { cout << "Arabic:" << value << endl; }
   private:
      int value;
}; // end class Arabic

int main() {
   Number z; //can't do anything with z
   Arabic a; a= 19;
   Roman  r; r= "XIX";
   cout << "Objects as themselves, no container ----------" << endl;
   z.show(); a.show(); r.show();

   Number n[3]; // Array of base class objects
   n[0]= z; n[1]= a; n[2]= r;
   cout << "Objects in container of baseclass ----------" << endl;
   n[0].show(); n[1].show(); n[2].show();

   Number *p_n[3]; // Array of pointers to Numbers
   p_n[0]= &z; p_n[1]= &a; p_n[2]= &r;
   cout << "Objects in container of baseclass pointers ----------" << endl;
   p_n[0]->show(); p_n[1]->show(); p_n[2]->show();

   return 0;
} // end main

This outputs the following.

Objects as themselves, no container ----------
No base class data!
Arabic:19
Roman:XIX
Objects in container of baseclass ----------
No base class data!
No base class data!
No base class data!
Objects in container of baseclass pointers ----------
No base class data!
Arabic:19
Roman:XIX

Note that the default access is private so by listing them before public, you can save that keyword. I think it’s better to just be explicit though.

Declarations will often need the class namespace. This looks like this.

retVar ClassName::somefunction(int x,int y);

The protected access control specifier means that the item specified is treated like public by derived classes and private from unrelated ones.

const Member Functions

If you have a situation like this

const Mything the_unchanging_thing= Mything("Always this.");
the_unchanging_thing.dump();

The dump member function probably won’t compile because the compiler can’t be sure that the dump() function won’t mess with the calling object. And since this particular calling object, the_unchanging_thing, is constant, that would be wrong.

The way to handle this is to define the dump() function as a "const Member Function" (that’s the official way to refer to it). Add the const keyword to the end of the declaration and definition.

void dump() const;

friend

Sometimes you want to give access to other functions that are actually not part of your class. This is what friend functions can do. Use friend keyword in the declaration, not the definition.

Confusingly, you must put the friend function declaration in the class it doesn’t belong to prefixed with the friend keyword.

friend MyClass operator+(double x, const MyClass &mc);

This now can go in the MyClass declaration even though it’s not part of MyClass. It’s just a helpful random function that can now access MyClass as if it were a part of it. Note that this example helps for this order of arguments. If the order is reversed, the MyClass operator+ can just be overloaded the normal way. It seems common to use friend functions when overloading operator<<().

Classes can be friends too. By doing something like this.

class Body {
  public:
    friend class Clothes;
  ...

This type of arrangement will allow Clothes to access Body’s private parts.

virtual

The virtual keyword is confusingly used for different purposes depending on context. Here are two of the uses. There may be more.

  1. A function declared virtual means that an existing overriding function in a derived class is invoked.

  2. An inheritance relationship declared using keyword virtual between classes Derived1 and Derived2 that inherits from class Base means that another class Derived3 that inherits from Derived1 and Derived2 still results in the creation of only one instance of Base during instantiation of type Derived3.

See Abstract Base Classes for an explanation of "pure virtual functions".

Abstract Base Classes

Taking some kind of obnoxious programming test? I had never heard of this and I suspect it has something to do with Java where abstract is a keyword; it is not in Cpp! But there are abstract base classes, sometimes referred to as ABC, in Cpp. An abstract base class is really just a class that contains one or more pure virtual functions. Class declarations containing at least one pure virtual function will not allow objects to be instantiated from that class.

A "pure virtual function" is one that ends with =0 like this.

void Move(int dx,dy) = 0;

That’s it. The =0 in the prototype means that the ABC doesn’t need to define the function. Also note the const member function version.

void Show(int dx,dy) const = 0; // But don't modify the calling object.

Member Initialization Lists

In class definitions the constructor can have a list of members with their correct initial values defined. These are placed after the constructor name and parameters, followed by a : and before the body of the constructor. The following are very similar. The first is preferred since it avoids unnecessary copies.

MyClass(int some_init_args):member1(5){}
MyClass(int some_init_args){member1=5}
Example of Member Initialization Lists
#include <iostream>
class Parent {
    public:
    Parent( int x ) {
        std::cout << "Parent's constructor"
        << " called with " << x << std::endl;
        }
    };

class Derived: public Parent {
    public:
    Derived() : Parent( 10 ) { // With "Member Initialization List".
        std::cout << "Derived's constructor" << std::endl;
        }
    };

class Strclass {
    public:
    Strclass() : thestr("This is the init string.") {
        std::cout << thestr << std::endl;
        }
    private:
    std::string thestr;
    };

int main() {
    Derived a_derived_instance;
    Strclass somesc;
    }

Exceptions

Recovering from errors in C is done by explicitly planning for every specific erroneous condition. In C++ there is a system of "exceptions" where (specifically) unanticipated errors can be treated reasonably.

While it is critical to understand exceptions I personally have some misgivings about them which are well documented in my Python notes. Without going into details here, I’ll sum up my personal opinion about C++ exceptions by quoting the Google C++ Style Guide which simply says, "We do not use C++ exceptions."

Here is a rough idea of how C++ exceptions work.

Example Of Exception Use
#include <iostream>
using namespace std;

void thefunction() { throw 99; }

int main (int argc, char *argv[]) {
    try {
        if (argc > 1){ thefunction();}
        else { throw '?';}   }
    catch(int e) {  // The catch is chosen based on its type.
        cout << "Exception number " << e << " has occured." << endl;
    }
    catch (...) {  // If the type sent by throw is not defined, go here.
        cout << "Unknown exception has occured." << endl;
    }
    return 0;
}

When this code is run with arguments it returns:

Exception number 99 has occured.

When this code is run without arguments it returns:

Unknown exception has occured.

Note that the catch statement is chosen based on the type specified by the throw command. In this simple example, this is not remarkable, but when defining your own types with classes, this mechanism can be very useful in organizing code to react to errors arising from different causes.

There are much fancier ways to use exceptions. You can define your own by inheriting standard exceptions. You can also catch and handle standard exceptions your own way. They can be nested such that the inner exception passes the information through to the outer ones.

Templates

Functions
template <typename T>
T functionName (T  parameter1,T  parameter2,...) { /* Function template. */ }

template <typename T1, typename T2>
T2 functionName (T1  parameter1,T2  parameter2,...) { /* Multiple types. */ }
Classes
template <class T>
class Number
{ private: T value; };

IntArray::IntArray(){ /* Normal constructor. */ }

template<class Type>
Array<Type>::Array(){ /* With template. */ }

Standard Template Library

The near universal detest for STL in game development makes each studio’s code a silo of private libraries, which is unfortunate.

You don’t use STL where you need max performance, but performance isn’t the top priority for most code, even in games.

I don’t like STL much and rarely use it, but I do really like standards. The library situation with C++ is really a shame.

#ID_AA_Carmack (2014-04-05)
— John Carmack

Both C and C++ are very spartan languages and in order to do anything useful in either you pretty much need to write some tools to manage simple flexible data structures. This has been thought out in C++ with the Standard Template Library or STL.

Note that in modern times the STL is actually a subset of the C++ standard library that was inspired by an ancient template library that got integrated. Another way to say "STL" is roughly something like "containers/iterators of the standard library".

STL mostly provides templates that allow programs to easily create simple but powerful data structures for all kinds of pragmatic uses. This is the kind of stuff that higher level languages like Javascript and Python take for granted.

Containers
Container Adaptors
  • priority_queue

  • queue

  • stack

Vector

A vector container is essentially a dynamic array. It has most of the advantageous properties of regular C arrays, mostly contiguous memory that can be accessed with predictable strides. Unlike regular C arrays, a vector can be dynamically resized as needs grow. This implies that vectors hog more memory than you may actually need them to, just in case you eventually want to use more than you thought you would. This also implies that once you use more than even this amount of memory, that an abrupt allocation of yet more memory may perhaps be needed along with a physical reshuffling of the contents; I don’t know if this can inject weird choppy performance issues, but it’s something to think about. The strategies used by vector to allocate additional memory are implementation dependent but seem to try to keep log(size) performance (adding twice as much a you had before when you run out).

The following sample program shows the basic STL container usage with a "vector" template.

#include <iostream>
#include <vector>
using namespace std;
int main() {
    vector<int> V1; // Define a vector of integers.
    V1.push_back(9); V1.push_back(6); V1.push_back(3); // Load vector.
    for (int i= 0; i<V1.size(); i++) { cout << V1[i] << endl; } // Display values.
    vector<int>::size_type v_st= V1.max_size(); // Note namespace to use size_type.
    cout << "Max number of elements in a Vector<int>: " << v_st << endl;
}

Methods for vector include:

  • empty - Tests if container is doing any containing.

  • push_back - In software engineering English "append". Relatively quick. Cpp11 emplace_back follows the plan of emplace.

  • pop_back - Remove item from end. Relatively quick.

  • insert - Arbitrary insertion. Maybe slow unless near the end and reallocation can be minimized. There is also Cpp11 emplace which allows construction and insertion.

  • erase - Arbitrary removal (not just clearing, item size() is decreased). Also maybe slow unless near the end. I’m not sure if memory is reallocated down ever with this method, but it could be.

  • size - How many elements defined and present.

  • capacity - How many elements have been automagically provisioned for before the next reallocation would be required.

  • resize - Tries to set the number of items to that specified. If there were more items, they get harshly jettisoned.

  • reserve - Like a faux gearshift lever for an automatic transmission, you can ask to manually meddle in the automatic memory allocation. Or how about Cpp11’s shrink_to_fit which may do what’s on the tin (including remapping the whole thing) or, interestingly, it may do nothing.

Deque

The double-ended queue is similar to a vector in that elements can be accessed with random access indexing. The major difference is that items can be inserted at the beginning of the array while vectors allow only the end to expand. As a consequence of this feature another difference is that the deque is not guaranteed to live in contiguous memory. This means that offset pointers can’t be used, as with vectors, to access other items; if you try it will produce random nonsense behavior. The deque uses complicated chunks of memory that it grows as needed where needed. By splitting the container internals, better edits may be possible from the middle of the object and excellent edits are expected at either end. This kind of structure might be ideal for a FIFO queue.

Methods for deque include:

  • push_back, push_front - Add an item to the end or beginning.

  • emplace_back, emplace_front - Compose and add item to end or beginning.

  • pop_back, pop_front - Remove an item from the end or beginning.

  • insert - Add item to arbitrary location.

  • emplace - Compose and add item to arbitrary location.

  • erase - Remove item from arbitrary location.

  • clear - Remove all items from container.

  • swap - Exchange contents of two deque objects.

  • size - Returns number of items.

  • empty - Check if container is containing.

  • resize - Set the container to a limited specified number of items, losing any surplus.

  • shrink_to_fit - Asks the container to try and refactor to minimize memory usage so that it is just sufficient to contain the current items. Note that this is mostly a courtesy and not guaranteed to do anything.

List

An STL list is a doubly-linked list. It’s quick to insert one or many anywhere, but slow to find particular items deep in the chain. This means that inserting can be slow if you need to find the insertion point first. However it also implies that editing the ends of the chain is going to be quick.

Methods for list include:

  • size - How many elements (not storage/bytes). max_size for architectural top end.

  • assign - Fill in a particular value for the whole list or just a range, three6s.assign(3,6). Can be used to do a deep copy with something like mytargetlist.assign(mysrclist.begin(),mysrclist.end()); Playing with the iterators there seems to be the way to get slice functionality.

  • insert - Add existing element. emplace to construct and add (all emplace functions are Cpp11) .

  • push_front,push_back - Replace push with emplace to construct and insert.

  • pop_front,pop_back

  • erase, clear - Removes an element or range. Or remove all content. Use empty to check if empty.

  • remove and remove_if - Removes elements that match specific values or other conditions.

  • unique - Remove duplicates.

  • reverse - Change the order of elements.

  • sort - Unadorned, uses <. Can use custom comparison function. Note the difference between this template method and the generic STL sort which requires a random access container. Stick with the built in list sort method for lists.

  • merge - Combine ordered lists into another ordered list.

  • splice - Move elements between lists.

Here is an example of using a linked list. One helpful feature is that you can insert into the beginning of the list without actually remapping everything else. This is a rough implementation of the Unix tac command which reverses lines of input. The reversing is done simply by inserting each line read into the list of lines instead of appending each.

#include <iostream>
#include <fstream>
#include <list>
using namespace std;

void readit(istream& ins,list<string>& lines){
    string line;
    while (getline(ins,line)){lines.push_front(line);}
}

int main(int argc,char** argv){
    list<string> lines;
    if (argc>1){ // A file name argument should be present.
        ifstream ifile(argv[1]);
        if (ifile.is_open()) { // Double check that it opened ok.
            readit(ifile,lines);
            ifile.close();
        }
        else // Can't open the file for some reason.
            cout<<"Error: Unable to open file for reading!!"<<endl;
    } else { // No arguments? Use standard input then.
        readit(cin,lines);
    }
    for (list<string>::iterator i=lines.begin();i!=lines.end();i++)
        cout<<*i<<endl;
    return 0;
}

Note also this program roughly shows how to handle reading standard input or a file specified. Also note that the reverse method could have been used, perhaps with slightly more clarity of purpose.

Other Lists

I have notes about a singly-linked slist but this appears to be nonstandard. And it looks like Cpp11 has forward_list for that purpose.

Map

A very simple demonstration of the most basic map syntax.

#include <iostream>
#include <map>
#include <string>
using namespace std;
int main () {
    map<string,int> piechart;
    piechart["C++"]=38;
    piechart["C"]=43;
    piechart["Python"]=19;
    cout << "C++'s value: " << piechart["C++"] << endl;
    cout << "C's value: " << piechart["C"] << endl;
    cout << "Python's value: " << piechart["Python"] << endl;
}

Reserved Keywords

asm, auto, bool, break, case, catch, char, class, const, const_cast,
continue, default, delete, do, double, dynamic_cast, else, enum,
explicit, export, extern, false, float, for, friend, goto, if, inline,
int, long, mutable, namespace, new, operator, private, protected,
public, register, reinterpret_cast, return, short, signed, sizeof,
static, static_cast, struct, switch, template, this, throw, true, try,
typedef, typeid, typename, union, unsigned, using, virtual, void,
volatile, wchar_t, while

cmath

Fancier math. Trig, logs, exp, sqrt, ceil, floor, abs. And wacky stuff like isnan.

#include <cmath>
M_PI // Is pi.
std::pow(base,exponent) // Exponents.
NAN // Is constant.

Set

A set is a container whose elements are always ordered (not sorted) and unique. Sets can be handy when trying to count unique items, even mildly complex ones as shown here with pair containers.

#include <iostream>
#include <utility>
#include <set>
using namespace std;
int main(void) {
    set<pair<int,int>> s;
    pair<int,int> p; // Not strictly necessary here.
    cout << s.size() << endl;    // Outputs: 0
    p.first= 0; p.second= 0; s.insert(p); // 1
    p.first= 1; p.second= 2; s.insert(p); // 2
    p.first= 3; p.second= 4; s.insert(p); // 3
    // Showing different way to compose set.
    s.insert(make_pair(5,6));             // 4
    s.insert(make_pair(1,2));    // Redundant, ignore.
    s.insert(make_pair(3,4));    // Redundant, ignore.
    cout << s.size() << endl;    // Outputs: 4
    return 0;
}
  • clear - Remove all elements from object.

  • insert - Put an item into the container. There is no sense of front or back since the item itself defines its place in the structure.

  • emplace - Composes and inserts an item. Also note emplace_hint which is similar but also takes a likely neighbor (one higher) and if that neighborhood is actually correct, the insert can be a lot quicker.

  • erase - Removes an item. This can be specified with the position index or by value which, in a set are pretty much the same thing.

Unordered Set

An unordered_set does not maintain an order. These can be quicker than regular sets. This is a Cpp11 thing.

Multiset

Allows duplicates.

  • find - Allows you to find the one or many items that match what you’re looking for.

Unordered Multiset

If you don’t want a strict ordering and you want duplicates to be valid, the unordered_multiset is a Cpp11 thing. For simplicity, imagine a Python dict where the keys are combined with an invisible nonce and there are no values; something like that.

Random

Newish C++ has a civilized library for random number generation. To use this fine library, I needed to compile with -std=gnu++11.

#include <random>
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(0,255);
int rand_red_value= distribution(generator);

This library seems pretty comprehensive. It features different PRNG engines and a bunch of distributions. See the official documentation for details.

Another way I’ve seen is something like this.

#include <time.h>
#include <cstdlib>
int main() {
srand(time(NULL));
int target= rand()%100; // 0-99
std::cout << target << std::endl;
return 0;}

Eigen Library Matrix Operations

Examples of working with Eigen matrices
VectorXd my_vector(2);     // Vertical vector of two elements.
my_vector << 10, 20;       // Comma initializer sets coefficients.
cout << my_vector << endl; // cout prints the vector

MatrixXd my_matrix(2,2);   // Initialize Matrix with 2x2 dimensions.
my_matrix << 1, 2,
             3, 4;         // Set matrix to contain [[1,2],[3,4]].
cout << my_matrix << endl; // cout prints a matrix

my_matrix(1,0) = 11;       // Access by position. 2nd row, 1st column.
my_matrix(1,1) = 12;       // 2nd row, 2nd column
my_matrix.row(i) = my_matrix2.col(i); // Get/set row/col vector.

MatrixXd x
x.setZero(rows, cols);     // Fill with zeros. Also a `setOnes()`.
x.setConstant(rows, cols, value); // Fill with value.
x.setRandom(rows, cols);   // Random values.

MatrixXd my_matrix_t = my_matrix.transpose(); // Transpose.
MatrixXd my_matrix_i = my_matrix.inverse();   // Inverse.
MatrixXd my_mtimesv= my_matrix * my_vector;   // Matrix multiplication.

Here’s a nice polynomial fitting routine which uses Eigen.

double polyeval(Eigen::VectorXd coeffs, double x) {
  double result = 0.0;
  for (int i = 0; i < coeffs.size(); i++) {result += coeffs[i]*pow(x, i);}
  return result;
}

Eigen::VectorXd polyfit(Eigen::VectorXd xvals, Eigen::VectorXd yvals, int order) {
  assert(xvals.size() == yvals.size());
  assert(order >= 1 && order <= xvals.size() - 1);
  Eigen::MatrixXd A(xvals.size(), order + 1);
  for (int i = 0; i < xvals.size(); i++) {
    A(i, 0) = 1.0;
  }
  for (int j = 0; j < xvals.size(); j++) {
    for (int i = 0; i < order; i++) {
      A(j, i + 1) = A(j, i) * xvals(j);
    }
  }
  auto Q = A.householderQr();
  auto result = Q.solve(yvals);
  return result;
}

Eigen::VectorXd xvals(6);
Eigen::VectorXd yvals(6);
xvals << 9.261977, -2.06803, -19.6663, -36.868, -51.6263, -66.3482;
yvals << 5.17,     -2.25,    -15.306,  -29.46,  -42.85,   -57.6116;
auto coeffs= polyfit(xvals,yvals,3);
std::cout<< "Y(16)=" << polyeval(coeffs,16) << endl;

This excellent resource explains a low impact way to do "Cubic Spline interpolation in C++ ".

Makefile

Here’s a very simple Makefile that can be used on very simple C++ programming tasks.

ALLSRCS:= $(wildcard *.cc)
ALLEXEC:= $(ALLSRCS:.cc=)
.PHONY:all clean
all: $(ALLEXEC)
%: %.cc
    g++ -o $@ $<
clean:
    rm $(ALLEXEC)

Profiling

Wondering what the heck is taking so long in your program? You can get hints about what your program spends its time doing.

Do this
    sudo apt-get install linux-tools
    sudo bash -c "echo 0 > /proc/sys/kernel/kptr_restrict"
    perf record ./yourprog --your-opts
    perf report
Get a nice report like this
 18.28%  yourprog  yourprog       [.] Plist::querypoint()                    ▒
 13.85%  yourprog  yourprog       [.] shallowanglecull(Llist*, Tlist*, float,▒
  8.70%  yourprog  yourprog       [.] Llist::querypointA()                   ◆
  7.00%  yourprog  yourprog       [.] Llist::querypointB()                   ▒
  6.73%  yourprog  yourprog       [.] Vector::compareto(Vector)              ▒
  5.76%  yourprog  yourprog       [.] searchlinelist(Plist*, Plist*, Llist*) ▒
  5.69%  yourprog  yourprog       [.] operator==(Vector, Vector)             ▒
  5.55%  yourprog  yourprog       [.] Vector::~Vector()                      ▒
  3.92%  yourprog  yourprog       [.] Tlist::BBinterfere(Llist*)             ▒
  3.59%  yourprog  yourprog       [.] searchtrilist(Plist*, Plist*, Plist*, T▒
  2.96%  yourprog  yourprog       [.] Tlist::querylink()                     ▒
  2.88%  yourprog  yourprog       [.] Llist::queryA()                        ▒
  2.26%  yourprog  yourprog       [.] BBinthelper(float, float, float, float,▒
  1.89%  yourprog  yourprog       [.] Vector::gg_valX()                      ▒
  1.25%  yourprog  yourprog       [.] Llist::querylink()                     ▒
  0.92%  yourprog  yourprog       [.] Tlist::querypointC()                   ▒
  0.91%  yourprog  yourprog       [.] find_matching_pnum(unsigned int, Plist*▒
  0.90%  yourprog  yourprog       [.] Vector::Vector()                       ▒
                ...

Or if that isn’t good enough check out gprof.

Actually this hack is quite clever too. See the other suggestions there too (e.g. Valgrind).

Resources For Optimizing