C++ Examples

C++ Examples

std::vector

  • std::vector<int> iv by itself is on the stack, but its data is on the heap

  • sizeof(std::vector<int>) is 24; it contains three 8-bytes pointers (on 64-bit machines)

    • one pointing to the beginning of the data on the heap

    • one pointing to the end of the data (size)

    • one pointing to the end of the allocated memory (capacity)

  • starting from empty, the capacity can grow to 1 2 4 8 16 ... under gcc compiler; it may differ under other compilers (e.g., MSVC)

  • essentially is a dynamic array: O(1) to insert at the end, but O(n) to insert elsewhere

std::vector<int> v; 
for(std::size_t i=0; i<10; ++i){
    v.push_back(i);
    std::cout << v.size() << " " << v.capacity() << std::endl;
}

for(auto i=v.begin(); i!=v.end(); ++i){
    std::cout << &*i << std::endl;  // print the address of each element
}

references: https://stackoverflow.com/questions/8036474/when-vectors-are-allocated-do-they-use-memory-on-the-heap-or-the-stackarrow-up-right; https://stackoverflow.com/questions/12271017/initial-capacity-of-vector-in-carrow-up-right; https://chryswoods.com/beginning_c++/lists.htmlarrow-up-right;

static_cast and dynamic_cast

The static cast performs conversions between compatible types. It is similar to the C-style cast, but is more restrictive. For example, the C-style cast would allow an integer pointer to point to a char.

Since this results in a 4-byte pointer pointing to 1 byte of allocated memory, writing to this pointer will either cause a run-time error or will overwrite some adjacent memory.

In contrast to the C-style cast, the static cast will allow the compiler to check that the pointer and pointee data types are compatible, which allows the programmer to catch this incorrect pointer assignment during compilation.

reference: https://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast/18414172#18414172arrow-up-right;

template and typename

  • typename needed by dependent names

reference: https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords/17579889#17579889arrow-up-right

  • template keyword is needed to tell the compiler explicitly that .cast is a template

references: Stackoverflow: When casting Eigen matrix type, error: expected primary-expression before ‘float’arrow-up-right

const

mutable

Recall that the const reference or pointer is constrained to

  • only read access for any visible data members,

  • permission to call only methods that are marked as const (because non-const member functions can write to data members, which breaks the fence).

The mutable keyword can allow you to modify a variable in a const method. It is like making exceptions for a few special variables.

references: https://stackoverflow.com/questions/105014/does-the-mutable-keyword-have-any-purpose-other-than-allowing-the-variable-toarrow-up-right;

reference

virtual function (for runtime polymorphism)

templated classes in cpp/hpp files & explicit instantiation

  • behavior: the templated classes can only be implemented in hpp files, but not cpp files

  • workaround: add explicit instantiation in the cpp files

  • reason in short: a template is literally a template; a class template is not a class, it's a recipe for creating a new class for each T we encounter

references: splitting templated classes into cpp/hpp filesarrow-up-right; why can templated only be implemented in the header filearrow-up-right; explicit template instantiation when is usedarrow-up-right

smart pointer vs. raw pointer

iterator

There are five types of iterator available in STL.

  • Bidirectional Iterator available for std::list,std::set and std::map

  • Random Access Iterator available for std::vector and std::deque

  • No iterator available for std::stack, std::queue and std::priority_queue

function pointer

reference: Stackoverflow: how to use boost bind with a member functionarrow-up-right; GeeksForGeeks: function pointer in Carrow-up-right; Function Pointers in C and C++arrow-up-right

ostream

  • keep in mind: streams are not copyable, but are movable

    • so that the copy constructor of any object that owns a stream won't work

    • because if a class has a non-copyable member then the containing class is also non-copyable

reference: Sending cout to a log filearrow-up-right

template specialization

  • Explicit (full) template specialization: Allows customizing the template code for a given set of template arguments.

  • Partial template specialization: Allows customizing class [and variable (since C++14)] templates for a given category of template arguments.

references: Stackoverflow: Template specialization with empty brackets and struct; cppreference: Explicit (full) template specialization; cppreference: Partial template specializationarrow-up-right; include/opencv2/core/traits.hpparrow-up-right

enum vs union

  • Enum: helps to assign constants to a set of names to make program easier to read, maintain and understand

    • Enums are not actual variables; they're just a semi-type-safe form of #define. They're a way of storing a number in a reader-friendly format. The compiler will transform all uses of an enumerator into the actual numerical value.

  • Union: helps to store data of different types as a single unit

references: Stackoverflow: what is the size of an enum type data in C++?arrow-up-right;

return multiple values

For returning two values we can use a std::pair (usually typedef'd). In C++11 and newer, there's std::tuple for more than two return results. With introduction of structured binding in C++17, returning std::tuple should probably become accepted standard.

In practice, if multiple result values are needed, the best practice is to create a struct to store these values and return this struct or change it as the pass-by-reference argument.

references: StackOverflow: Returning multiple values from a C++ functionarrow-up-right; Open3D/ColoredICParrow-up-right; TEASER-plusplus/include/teaser/registration.harrow-up-right

std::thread

  • template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );

  • Move constructor is allowed, but copy constructor is deleted.

  • If running class member functions, an instance of the class is needed as the first argument.

references: C++ reference on std::thread constructorarrow-up-right; slambook2 chapter 13 source codearrow-up-right; LeGO-LOAM map optimization source codearrow-up-right; A-LOAM mapping source codearrow-up-right;

volatile

  • It is a keyword to tell compiler that this variable may be modified from outside the program which compiler is not aware of. Therefore, please do not optimize this variable.

  • It is a qualifier that can also be applied to methods/functions.

  • volatile and const are two faces of the same coin.

references: C++ keywords: volatilearrow-up-right; https://stackoverflow.com/questions/4437527/why-do-we-use-volatile-keywordarrow-up-right; https://stackoverflow.com/questions/4479597/does-making-a-struct-volatile-make-all-its-members-volatile/4479652arrow-up-right;

memory fence/barrier

  • This refers to a set of instructions to synchronize memory access (read/writes occur in the order you expect). For example a 'full fence' means all read/writes before the fence are comitted before those after the fence. It is a hardware level concept, and in higher level languages we are used to dealing with mutexes and semaphores.

  • Note that the keyword volatile does not guarantee a memory barrier to enforce cache-consistency. Although It is guaranteed that volatile reads/writes will happen in the exact order specified in the source code, but volatile reads/writes can still be reordered with respect to non-volatile ones. (This is referred to as compiler reordering optimizations.)

Thread #1 Core #1:

Thread #2 Core #2:

references: https://stackoverflow.com/questions/1525189/do-i-need-a-mutex-for-readingarrow-up-right; https://en.wikipedia.org/wiki/Memory_barrierarrow-up-right; https://stackoverflow.com/questions/286629/what-is-a-memory-fencearrow-up-right;

hash

By default, std::pair and std::tuple are not hashable, and therefore they cannot serve as keys in std::unordered_map. For hashing and combining multiple values, one way is to use boost::hash_combine function. Alternatively, we can write our own hash functions.

References: https://stackoverflow.com/questions/20511347/a-good-hash-function-for-a-vector/arrow-up-right; https://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-keyarrow-up-right; https://wjngkoh.wordpress.com/2015/03/04/c-hash-function-for-eigen-matrix-and-vector/arrow-up-right

class inheritance and polymorphism

factory method

The most basic factory method

Reference: Unforgettable Factory Registrationarrow-up-right

Last updated

Was this helpful?