Wednesday, October 26, 2016

C++ tips, 2016 Week 42 (17-Oct - 23-Oct-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. Using parameter pack to write one_of
This one is from Jason Turner (here and here). Instead of writing:
if (thing.x == 1 || thing.x == 2 || thing.x == 3)
you can write:

template<typename U, typename ... T> 
bool one_of(U&& u, T && ... t) 
{
  return ( (u == t) || ...  ); 
}

or you can use the initializer_list ordered evaluation trick:

template<typename U, typename ... T> 
bool one_of(U&& u, T && ... t) 
{ 
bool match = false; 
(void)std::initializer_list<bool>{ (match = match || u == t)... }; 
return match; 
} 

usage:

struct Thing 
{ 
int x = 3; 
};

Thing thing;
auto v1 = one_of(thing.x, 1, 2, 3, 4);

2. Type-Safe Unions in C++

Taken from Nick Sarten's blog ( Type-Safe Unions in C++ and Rust )

struct Connection { 
 std::string m_serverAddress; 
  
 struct Disconnected {}; 
 struct Conecting {}; 
 struct Connected { 
     ConnectionId m_id; 
     std::chrono::system_clock:time_point m_connectedTime; 
     std::chrono::milliseconds m_lastPingTime; 
 }; 
 struct ConnectionInterrupted { 
     std::chrono::system_clock::time_point m_disconnectedTime; 
     Timer m_reconnectTimer; 
 }; 
  
 std::variant<Disconnected, 
              Connecting, 
              Connected, 
              ConnectionInterrupted> m_connection; 
};

and than use std::visit:

std::visit( 
[](auto&& con) {  
using T = std::remove_cv_t<std::remove_reference_t<decltype(con)>>; 
if constexpr (std::is_same_v<T, Connection::Disconnected>) 
std::cout << "Connection disconnected" << std::endl; 
else if constexpr (std::is_same_v<T, Connection::Connecting>) 
std::cout << "Connection connecting..." << std::endl; 
 else if constexpr (std::is_same_v<T, Connection::Connected>) 
std::cout << "Connection id " << con.m_id << " connected for " << con.m_connectedTime << std::endl; 
else if constexpr (std::is_same_v<T, Connection::ConnectionInterrupted>) 
std::cout << "Connection interrupted!" << std::endl; 
}, 
conn 
)

3. GotW #102: Exception-Safe Function Calls 

I was very lazy that day and I just posted a link to GotW #102: Exception-Safe Function Calls

Where Herb Sutter explains why you should use:

// In some header file: 

void f( std::unique_ptr<T1>, std::unique_ptr<T2> ); 

 

// At some call site: 

f( make_unique<T1>(), make_unique<T2>() ); 


instead of:
f( std::unique_ptr<T1>{ new T1 }, std::unique_ptr<T2>{ new T2 } ); 
 or naked pointer interfaces with new in the function call.

4. Special Member Function

Taken from this presentation by Howard Hinnant:



5. boost::intrusive_ptr

(based in this article by Baptiste Wicht)

boost::intrusive_ptr is a smart pointer that hold the reference counting within the object that is reference counted. In order to do that you need to add two functions (and a member to your class) to indicate how the reference counting is happening. For example:

class Foo { 
   ...... 
 
   long references = 0; 
};

and the two function:

inline void intrusive_ptr_add_ref(Foo * x) { 
   ++x->references; 
} 
inline void intrusive_ptr_release(Foo * x) { 
   if(--x->references == 0) 
   delete x; 
}

and use it similar to std::shared_ptr

void test() { 
   boost::intrusive_ptr<Foo > x(new Foo ); 
   std::cout << x->name << std::endl; 
}

Note! you can also derive from boost::intrusive_ref_counter to avoid writing all that boilerplate code 

Pros:
  • gain data locality and potential performance improvement for classes that are very often dynamically allocated
  • two intrusive_ptr-s for one object use the same ref counter where if you create two shared_ptr-s for one object they will have two different ref counters
Cons
  • you can not create weak_ptr from intrusive_ptr
  • you have to modify your classes to be usable with intrusive_ptr
Advice:
  • Use intrusive_ptr only in performance critical code after determining it by measurements 
  • On the non-performance critical code use std smart pointers to avoid bloating the code base unnecessarily 


Thanks for reading