1. 替换rand函数
C++11的一个重大进展就是使用random header中提供的所有选项替换rand()
函数。在许多情况下,替换rand()
应该是很简单的。
Stephan T. Lavavej在他的演示文稿rand() Considered Harmful中可能是最强烈地表达了这一点。示例展示了如何使用rand()
生成介于[0,10]
之间的均匀整数分布:
#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 ;
}
并使用 std::uniform_int_distribution:
#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 ;
}
随着
Deprecate rand and Friends的努力,我们应该从
std::random_shuffle转移到
std::shuffle。最近在SO问题
Why are std::shuffle methods being deprecated in C++14?中也有相关讨论。
请注意,分布在不同平台上并不保证
consistent across platforms。
2. 使用std::to_string而不是std::ostringstream或sprintf
C++11提供了
std::to_string,可用于将数字转换为
std::string,它会生成与等效的
std::sprintf内容。最有可能使用它来替代
std::ostringstream或
snprintf
。这更多是一种方便,性能差异可能不大,我们可以从
Fast integer to string conversion in C++文章中看到,如果性能是主要问题,则可能有更快的替代方法:
#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. 使用constexpr代替模板元编程
如果你正在处理字面量,使用constexpr函数而不是模板元编程可能会产生更清晰的代码,并且可能编译得更快。文章想要速度?使用constexpr元编程!提供了一个使用模板元编程确定质数的示例:
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 };
};
并使用constexpr函数:
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);
}
constexpr版本更短,易于理解,并且表现明显优于模板元编程实现。
4. 使用类成员初始化提供默认值
正如最近在新的C++11成员初始化特性是否已经使初始化列表过时?中介绍的那样,可以使用类成员初始化来提供默认值,并且可以简化具有多个构造函数的类的情况。
Bjarne Stroustrup在C++11 FAQ中提供了一个很好的例子,他说:
这可以节省一些打字,但真正的好处在于具有多个构造函数的类。通常,所有构造函数都使用成员的公共初始化器:
并提供了具有公共初始化器的成员的示例:
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;
std::string s;
};
并说:
哈希算法和s每个都有一个默认值的事实在代码混乱中丢失了,很容易在维护过程中成为问题。相反,我们可以将数据成员的初始化分解出来:
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"};
std::string s{"Constructor run"};
};
注意,在C++11中,使用类内成员初始化器的类
不再是一个聚合体,尽管这个限制在C++14中被取消了。
5. 使用cstdint中的固定宽度整数类型而不是手动定义的typedef
由于C++11标准使用C99作为规范参考,我们也得到了
固定宽度整数类型。例如:
int8_t
int16_t
int32_t
int64_t
intptr_t
尽管其中几个是可选的,但对于确切宽度的整数类型,适用于C99第7.18.1.1节的以下内容:
“这些类型是可选的。但是,如果实现提供了宽度为8、16、32或64位、没有填充位并且(对于有符号类型)具有二进制补码表示的整数类型,则应定义相应的typedef名称。”
.data()
而不是&container[0]
有个限制。这对于std::string
是不起作用的,因为.data()
对于std::string
来说与.c_str()
相同,返回一个常量指针。另外,在MSVC2013中,push_back
使用T&&
,等同于emplace_back
。 - Brandonoverride
关键字来表明一个函数是覆盖了基类中的虚函数,而不是引入了一个新的函数或者隐藏了基类中的函数。此外,我建议不要将每个类都声明为 final。应该谨慎使用,因为它会使得测试代码比必要的更加繁琐。 - sdkljhdf hda