1. Rand replacement
One of the big winnings in C ++ 11 is to replace the use of rand() all the parameters available in a random header . Replacing rand() in many cases should be straightforward.
Stefan T. Lawave probably made this moment the strongest with his presentation of rand () considered harmful . The examples show a uniform integer distribution from [0,10] using rand() :
#include <cstdlib> #include <iostream> #include <ctime> int main() { srand(time(0)) ; for (int n = 0; n < 10; ++n) { std::cout << (rand() / (RAND_MAX / (10 + 1) + 1)) << ", " ; } std::cout << std::endl ; }
and using std :: uniform_int_distrubution :
#include <iostream> #include <random> int main() { std::random_device rd; std::mt19937 e2(rd()); std::uniform_int_distribution<> dist(0, 10); for (int n = 0; n < 10; ++n) { std::cout << dist(e2) << ", " ; } std::cout << std::endl ; }
Along with this, we should move from std :: random_shuffle to std :: shuffle , which comes from the efforts to Cancel rand and friends . This was recently covered in a SO question. Why are std :: shuffle methods deprecated in C ++ 14? .
Please note that distributions are not guaranteed for different platforms .
2. Using std :: to_string instead of std :: ostringstream or sprintf
C ++ 11 provides std :: to_string , which can be used to convert numbers to std :: string , this will create content as equivalent to std :: sprintf . Most likely, this will be used instead of std :: ostringstream or snprintf . This is more convenient, there is probably not much difference in performance, and we can see from the Fast integer for converting strings to C ++ . probably much faster alternatives if performance is a major issue:
#include <iostream> #include <sstream> #include <string> int main() { std::ostringstream mystream; mystream << 100 ; std::string s = mystream.str(); std::cout << s << std::endl ; char buff[12] = {0}; sprintf(buff, "%d", 100); std::string s2( buff ) ; std::cout << s2 << std::endl ; std::cout << std::to_string( 100 ) << std::endl ; }
3. Using constexpr instead of template metaprograms
If you are dealing with literals, there may be times when using constexpr functions over a template metaprogram can lead to a clearer and possibly compiler code. Article Want speed? Using metaprogramming constexpr! gives an example of determining a prime using template metaprograms:
struct false_type { typedef false_type type; enum { value = 0 }; }; struct true_type { typedef true_type type; enum { value = 1 }; }; template<bool condition, class T, class U> struct if_ { typedef U type; }; template <class T, class U> struct if_<true, T, U> { typedef T type; }; template<size_t N, size_t c> struct is_prime_impl { typedef typename if_<(c*c > N), true_type, typename if_<(N % c == 0), false_type, is_prime_impl<N, c+1> >::type >::type type; enum { value = type::value }; }; template<size_t N> struct is_prime { enum { value = is_prime_impl<N, 2>::type::value }; }; template <> struct is_prime<0> { enum { value = 0 }; }; template <> struct is_prime<1> { enum { value = 0 }; };
and using constexpr functions:
constexpr bool is_prime_recursive(size_t number, size_t c) { return (c*c > number) ? true : (number % c == 0) ? false : is_prime_recursive(number, c+1); } constexpr bool is_prime_func(size_t number) { return (number <= 1) ? false : is_prime_recursive(number, 2); }
The constexpr version is much shorter, easier to understand and, apparently, much better than the implementation of template metaprograms.
4. Using class member initialization to provide default values
As recently discussed in, Was a new C ++ 11 member initialization function introduced in an declaration made by initializing obsolete lists? to initialize a class member to provide default values ββand may simplify cases where a class has multiple constructors.
Bjarne Stroustrup is a good example in the C ++ 11 FAQ, he says:
This saves a bit of input, but the real benefits come in classes with multiple constructors. Often, for all constructors, a regular member initializer is used:
and provides an example of elements that share a common initializer:
class A { public: A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {} A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {} A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {} int a, b; private: HashingFunction hash_algorithm;
and says:
The fact that hash_algorithm and s each has one default is lost in a mess of code and can easily become a problem during maintenance. Instead, we can eliminate the initialization of data members:
class A { public: A(): a(7), b(5) {} A(int a_val) : a(a_val), b(5) {} A(D d) : a(7), b(g(d)) {} int a, b; private: HashingFunction hash_algorithm{"MD5"};
Note that in C ++ 11, a class that uses a class member in initializers is no longer an aggregate , although this restriction has been removed in C ++ 14.
5. Use integer fixed-width types from cstdint instead of manual typedefs
Since the C ++ 11 standard uses C99 as a normative reference, we get fixed widths of integer types . For example:
int8_t int16_t int32_t int64_t intptr_t
Although some of them are optional, for exact integers of width the following applies from section C99 7.18.1.1 :
These types are optional. However, if the implementation provides integer types with a width of 8, 16, 32, or 64 bits, without padding bits and (for signed types) that have a double padding representation, it must define the appropriate typedef names.