keywords: C++, Advanced Features Notes, Tutorials

Fragments

Dependency Injection

Dependency Injection in C++
https://vladris.com/blog/2016/07/06/dependency-injection-in-c.html

Anonymous Namespaces

Unnamed/anonymous namespaces vs. static functions
https://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions

Dynamic Initialization & Static Initialization

C++ - Initialization of Static Variables
https://pabloariasal.github.io/2020/01/02/static-variable-initialization/

constexpr vector and string in C++20 and One Big Limitation
https://www.cppstories.com/2021/constexpr-vecstr-cpp20/

Polymorphic Allocator

std::pmr::polymorphic_allocator
https://en.cppreference.com/w/cpp/memory/polymorphic_allocator

polymorphic_allocator: when and why should I use it?
https://stackoverflow.com/questions/38010544/polymorphic-allocator-when-and-why-should-i-use-it

Polymorphic Allocators, std::vector Growth and Hacking
https://www.bfilipek.com/2020/06/pmr-hacking.html

Call Stack

print call stack in C or C++
https://stackoverflow.com/a/54365144/1645289

Comment

pragma region example:

// pragma_directives_region.cpp
#pragma region Region_1
void Test() {}
void Test2() {}
void Test3() {}
#pragma endregion Region_1

int main() {}

Platform

Endianness (Byte Order)

Let’s say your data stream has a little-endian-encoded 32-bit integer. Here’s how to extract it (assuming unsigned bytes):

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

If it’s big-endian, here’s how to extract it:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

Origin:
How do I convert between big-endian and little-endian values in C++?
https://stackoverflow.com/a/10346064/1645289

Performance

Move Semantics

What is move semantics?
https://stackoverflow.com/questions/3106110/what-is-move-semantics
Difference between copy constructor and move constructor
https://stackoverflow.com/a/3106136/1645289

Exception

There is a cost associated with exception handling on some platforms and with some compilers.

Namely, Visual Studio, when building a 32-bit target, will register a handler in every function that has local variables with non-trivial destructor. Basically, it sets up a try/finally handler.

The other technique, employed by gcc and Visual Studio targeting 64-bits, only incurs overhead when an exception is thrown (the technique involves traversing the call stack and table lookup). In cases where exceptions are rarely thrown, this can actually lead to a more efficient code, as error codes don’t have to be processed.

Quoted from:
In what ways do C++ exceptions slow down code when there are no exceptions thown?
https://stackoverflow.com/a/1897979/1645289

std::align (alignas & alignof)

Little C++ Standard Library Utility: std::align
https://lesleylai.info/en/std-align/

Compilation

How to use two libraries if they have same function in C

If you have .o files there, a good solution:

objcopy --prefix-symbols=pre_string test.o to rename the symbols in .o file

or

objcopy --redefine-sym old_str=new_str test.o to rename the specific symbol in .o file.

Origin:
https://stackoverflow.com/a/41375697/1645289

C

Memory

Why is the use of alloca() not considered good practice?
https://stackoverflow.com/questions/1018853/why-is-the-use-of-alloca-not-considered-good-practice

STL

new(std::nothrow)

std::nothrow
https://en.cppreference.com/w/cpp/memory/new/nothrow

lock_guard (RAII)
std::mutex m;
 
void bad() 
{
    m.lock();                    // acquire the mutex
    f();                         // if f() throws an exception, the mutex is never released
    if(!everything_ok()) return; // early return, the mutex is never released
    m.unlock();                  // if bad() reaches this statement, the mutex is released
}
 
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization
    f();                               // if f() throws an exception, the mutex is released
    if(!everything_ok()) return;       // early return, the mutex is released
}

Origin:
https://en.cppreference.com/w/cpp/language/raii

Lambda

this vs &

C++ lambda capture this vs capture by reference
https://stackoverflow.com/questions/33575563/c-lambda-capture-this-vs-capture-by-reference

= VS & (Value vs Reference)

Quick example

int x = 1;
auto valueLambda = [=]() 
{
    cout << x << endl;
};
auto refLambda = [&]() 
{
    cout << x << endl;
};
x = 13;
valueLambda();
refLambda();

Output:

1
13

Is there any difference betwen [=] and [&] in lambda functions?
https://stackoverflow.com/a/21105182/1645289

shared_ptr with Lambda

C99

template<typename T, typename F>
class shared_this_lambda {
  std::shared_ptr<T> t;  // just for lifetime
  F f;
public:
  shared_this_lambda(std::shared_ptr<T> t, F f): t(t), f(f) {}
  template<class... Args>
  auto operator()(Args &&...args)
  -> decltype(this->f(std::forward<Args>(args)...)) {
    return f(std::forward<Args>(args)...);
  }
};

template<typename T>
struct enable_shared_this_lambda {
  static_assert(std::is_base_of<std::enable_shared_from_this<T>, T>::value,
    "T must inherit enable_shared_from_this<T>");

  template<typename F>
  auto make_shared_this_lambda(F f) -> shared_this_lambda<T, F> {
    return shared_this_lambda<T, F>(
      static_cast<T *>(this)->shared_from_this(), f);
  }

  template<typename F>
  auto make_shared_this_lambda(F f) const -> shared_this_lambda<const T, F> {
    return shared_this_lambda<const T, F>(
      static_cast<const T *>(this)->shared_from_this(), f);
  }
};

Usage

doSomethingAsynchronously(make_shared_this_lambda([this] {
  someMember_ = 42;
}));

Orgin: Using C++11 lambdas asynchronously, safely

weak_ptr with Lambda

Example:

std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
return std::function<void()>([thisWeakPtr]()
{
  auto myPtr = thisWeakPtr.lock();
  if(myPtr)
    myPtr->CallbackFunc()
});

Origin: Binding to a weak_ptr

Case 01:

void Process(FRDGBuilder& Builder)
{
    AsyncLoad([Builder](FRenderData& Data)  //this fires compilation error
        {
            Builder.CreatBuffer(Data);
        });
}

Compiliation error:

error C2663: 'FRDGBuilder::CreateBuffer': 2 overloads have no legal conversion for 'this' pointer

Solution:

void Process(FRDGBuilder& Builder)
{
    AsyncLoad([&Builder](FRenderData& Data)
        {
            Builder.CreatBuffer(Data);
        });
}

Type support

offsetof

The macro offsetof expands to an integral constant expression of type std::size_t, the value of which is the offset, in bytes, from the beginning of an object of specified type to its specified subobject, including padding bits if any.

References:
Type support (basic types, RTTI)
https://en.cppreference.com/w/cpp/types

Reference

Blogs

Barry Revzin (Recommended)
https://brevzin.github.io/

Modernes C++
https://www.modernescpp.com/index.php/

Categories for the Working C++ Programmer
https://bartoszmilewski.com/2020/08/05/categories-for-the-working-c-programmer/amp/

<bit> in Visual Studio 2019 version 16.8 Preview 2
https://devblogs.microsoft.com/cppblog/bit-in-visual-studio-2019-version-16-8-preview-2/


Rank does not confer privilege or give power. It imposes responsibility. ― Peter Drucker