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.
List of all weekly posts can be found here.
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
No comments:
Post a Comment