Thursday, December 1, 2016

C++ tips, 2016 Week 47 (21-Nov - 27-Nov-2016)

This is part of my weekly C++ posts based on the daily C++ tips I make at my work. I strongly recommend this practice. If you dont have it in your company start it. 
List of all weekly posts can be found here.

1. C++ is not going anywhere

That's the tip - it is a motivational one. I hear so many people announcing the death of C++ and how it is in decline and it is over. Even from within our community. Yet now there are more C++ developers than ever. Yes - other languages grow faster and the share of C++ is not growing but that is OK. It should be expected - we cant use C++ for everything. It does not make any sense.

The Committee is doing tremendous amount of work to add new features to the language without breaking 20+ years legacy code bases. Look at the current state (from Herb Sutter's Trip report: Fall 2016 ISO C++ standards meeting (Issaquah) ):



(also check Botond Ballo trip report from Issaquah. Its awesome)

Tons of new features are coming into the language! Exciting times! So, please, stop the gloom and doom. C++ is not going anywhere.

2. noexcept move operations

Always try to make your move assignment and move constructor noexcept. The reason for this is STL is noexcept-aware and it does a lot less when it knows there will be no exception trowing during the movement of elements in the containers.

For example std::vector must be able to restore the previous state if something trows during reallocation (when calling emplace_back(...) for example). Knowing that nothing will trow opens the door for optimizations.

In general you should try to make as much functions noexcept as possible.

More info here: Declaring the move constructor by Andrzej Krzemieński and Make Your Code Faster with noexcept by Kate Gregory

3. boost::protect

This one was suggested by my friend Alexander Cheshmedjiev also C++ User Group Sofia organizer.

boost::protect is used when you dont want to evaluate the arguments passed to bind. For example (f1 takes function as parameter):

void f1(boost::function<void()> f) 
{ 
   f(); 
} 
auto bf1 = boost::bind(f1,  
                      boost::bind(foo, 3));

will fail to compile with a nasty unreadable error because the second boost::bind will be evaluated before being passed to the first boost::bind.

auto bf1 = boost::bind(f1, 
                    boost::protect(boost::bind(foo, 3)));


Now everything works fine and as expected.

The full example written by him can be found here: boost::protect example

4. std::addressof 

std::addressof obtains the actual address of the object or function, even in the presence of overloaded operator&. Imagine you are super paranoid that someone will constantly overload your operators. This is the way to get the pointer without worrying.
static_assert( std::addressof(x) == &x, "Someone overloaded operator&. Unacceptable!" ); 
Note. Its rvalue overload is deleted to prevent taking the address of const rvalues.

5. Voldemort types

Consider this:

#include <iostream> 
 
auto funct() 
{ 
   struct Volde{ 
       int a = 5; 
   }; 
   return Volde(); 
} 
int main() 
{ 
   auto mort = funct(); 
   // Volde plsCompile; // compilation error 
   std::cout << mort.a; 
}


We are able to use the the local struct Volde outside the function using auto. However if we try to use it without auto we get a compilation error.

Those types are called Voldemort types and are common in D but also in C++ from C++14.

You are basically forced to use them only with auto. This way the implementation details are encapsulated away from the user and you are allowed to use only the primitives.

funct() can return any type and main will compile and work as long as all of the return types have a member a.

I overheard this on twitter from sehe

No comments:

Post a Comment