Posts

C++ Guidelines for Multithreaded System

Image
Mutithreading è Parallelism è  Achieve concurrency. Below are some of the guidelines to follow for building C++ Multithreaded system. Ø std::thread function arguments are pass by value by default. Thread function arguments are pass by value by default. So, if you want the change to be persisted in the arguments passed in , then pass them by reference using std::ref(). Ø Protect shared data or resource using critical section.     In a multithreaded environment if there are more than one thread sharing the resource/data then often it results in a undefined behaviour if the resource/shared data is not protected using synchronise mechanism. So, the shared resource/data must be protected with std::mutex . Ø Release lock after critical section. If a thread T1 acquires lock (mutex.lock()) before entering critical section and forgets to unlock(mutex.unlock()) then all the other threads will be blocked indefinitely and the program might hang because thread T1 gets hol

Declaring const_iterator vs declaring an iterator const

An iterator acts much like a T* pointer.  Declare an iterator const Declaring an iterator const is nothing but declaring a const  pointer which is equivalent to T* const - iterator is not allowed to point to different object, but the data iter points to can be modified.  Lets look at an example below : std::vector<std::string> vecOfStrings; // Push some strings to the vector // Declare an iterator const const std::vector<string>:: iterator iter; // iter acts like T* const , const pointer iter = vecOfStrings.begin(); *iter = "newValue"; // Ok, changes the value what iter points to. ++iter; // Compilation error , iter is const Declare an const_iterator Declaring an const_iterator is nothing but declaring an pointer to const object which is equivalent to const T* - Iterator can point to different object but modifying the data will throw an compilation error. Let's look at an example below : std::

Times when compiler refuses to generate default functions.

Generally C++ compiler generates default functions like Constructor, Copy Constructor, Copy Assignment operator and Destructor if not defined. But there are some cases when compiler also refuses to generate these functions. Consider the below example : name  is a reference and age  is a const T. template<typename T> class PersonObject { public: // this ctor no longer takes a const name, because name // is now a reference-to-non-const string. The char* constructor // is gone, because we must have a string to refer to. NamedObject(std::string& name, const T& age); ... // as above, assume no // operator= is declared private: std::string & name; // this is now a reference const T age ; // this is now const }; Now consider what should happen here: string person1("Tom"); string person2("Mike"); PersonObject<int> p1 (person1, 24); PersonObject<int> p2 (person2, 30); p1 = p2;   // What should happen to the data

Parenthesis Confusion while creating objects

Parenthesis Confusion while creating objects - C++ Let's see some notations of trying to create objects in different ways of creating objects ClassName obj1; ClassName obj2(); ClassName *obj3 = new ClassName; ClassName *obj4 = new ClassName(); So, which and all the above statements create objects: ClassName obj1 - Yes. Object obj1 is created on stack. ClassName obj2(); - No. C++ compiler will interpret "obj2" as a function definition with no parameters and which returns a ClassName object. ClassName *obj3 = new ClassName; - YES obj3 will be created as a default initialized, which means all POD data types will be left unitialized. ClassName *obj4 = new ClassName(); - YES obj4 will be created as a value initialized, which means all data members will be initialized. Init will be zero-initialized. So, what is a POD class ? POD means "Plain Old Data". In C++, objects are either POD or non-POD. A POD class is said to have data m

std::shared_mutex

std::shared_mutex are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so. To protect shared data from being simultaneously accessed by multiple threads. #include<iostream> #include<mutex> #include<shared_mutex> #include<thread> class MutipleReaderSingleWriter {           int get() const           {                    std::shared_lock <std::shared_mutex> lock(mutex_);                    return _value;           }           void increment()           {                    std::unique_lock <std::shared_mutex> lock(mutex_);                     _value++;           }                     private:                    mutable std::shared_mutex mutex_;                    int _value = 0; }; int main() {           MutipleReaderSingleWriter list;                     auto incrementAndPrint = [&list

std::weak_ptr

std::weak_ptr std::weak_ptr is'nt a standalone smart pointer. It's an augmentation of std::shared_ptr.  It do not contribute to the reference count of the managed object they refer to. By using just the raw pointer, it is impossible to know if the referenced data has been deallocated or not. std::weak_ptr provides a "expired" API to check if the shared_ptr it was pointing to is expired. In a nutshell - The weak_ptr class template stores a “weak reference” to an object that’s already managed by a shared_ptr . To access the object, a weak_ptr can be converted to a shared_ptr using the shared_ptr constructor or the member function lock. When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail: the constructor will throw an exception of type boost::bad_weak_ptr, and weak_ptr::lock will return an empty shared_ptr . auto

Rvalue references vs Universal references

Whenever we see " T&& " it seems reasonable to assume that we are referring to "rvalue reference", but it's not. " T&& " has two different meanings - rvalue reference universal reference. For instance, below all are rvalue references because the types are known and not deduced. void fun(Base&& aObj); // rvalue reference Base&& a = Base();            // rvalue reference Universal references below in which the type is deduced. The most common is function template and auto declarations. template<typename T> void f(T&& param);     // param is being deduced, a universal reference auto&& obj2 = obj1;   // obj2 is a universal reference If we look at "T&&" without type deduction, it;s an rvalue reference. Universal reference can accept both rvalue and lvalue references, but they must be initialized.  If the initializer is rvalue, the universal refere