C++11新特性
0、使用C++11新特性,编译时需指定-std=c++11。
1、auto与decltype:自动类型推导。
如auto x = 7;,则推导x是int类型的。auto在类型难以确切知道或难以表达时很有用:
template<class T, class U> void compute(T t, U u) { // x的类型在事先难以确切知道 auto x = t * u; cout << sizeof(x) << endl; } int main() { compute<int, int>(1, 1); // 4 compute<int, double>(1, 1.2); // 8 vector<int> vec = {1, 2, 3, 4}; // “传统的”遍历方式 // for (vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) // 简洁写法 // for (auto iter = vec.begin(); iter != vec.end(); iter++) // 这种情况下,还可以这样遍历 // for (auto ele : vec) return 0; }
auto的另一个好处是,使用它定义的变量都必须初始化。
decltype操作符用于取得操作数类型。如下例:
int main() { int i = 0; decltype(i) j = i; // &i != &j decltype((i)) k = i; // k为int &类型。&i == &k int a[10] = {10}; decltype(a) b; // b为数组类型。sizeof(b) == 40 int c[3] = {1, 2, 3}; // decltype(c[1]) d; // d为引用类型。因为没有初始化而报错 return 0; }
2、std::enable_if
template <bool Cond, class T = void> struct enable_if {};
若Cond为true则enable_if::type被设置为T,否则enable_if::type未定义(会导致编译出错)。示例:
#include <type_traits> // 用法一 template <class T> typename std::enable_if<std::is_integral<T>::value, bool>::type // is_integral::value为true时enable_if::type被设置为bool is_odd (T i) {return bool(i % 2);} // 用法二 template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type> bool is_even (T i) {return !bool(i % 2);} int main() { short int i = 1; std::cout << std::boolalpha; std::cout << "i is odd: " << is_odd(i) << std::endl; std::cout << "i is even: " << is_even(i) << std::endl; float f = 1.0; // std::cout << "f is odd: " << is_odd(f) << std::endl; // 编译出错 return 0; }
3、lambda表达式
1)简介:一种描述函数对象的机制。它可以访问它所在作用域内的局部变量(如第二个例子)。
2)示例:
int main() { vector<int> v = {50, -10, 20, -30}; // 根据绝对值排序。第三个参数即为lambda表达式/函数 sort(v.begin(), v.end(), [](int a, int b) { return abs(a) < abs(b); }); return 0; }
int main() { vector<int> vec(8); int count = 0; // 最终vec的元素为0~7 generate(vec.begin(), vec.end(), [&count]() { return count++; }); return 0; }
[]部分称为“捕获”(capture)列表。
[&count]表示lambda表达式以引用方式“捕获”count,可以修改它。改成[]会报错,因为若没有“捕获”count则不能访问它;改成[count](值方式“捕获”)也会报错,因为此时count是只读的。另外,[]表示不“捕获”任何变量,[&]表示以引用方式“捕获”所有(可“捕获”的)变量,[=]表示以值方式“捕获”所有(可“捕获”的)变量。
4、std::function和std::bind
bind和function标准函数对象定义在<functional>中。它们被用于处理函数和函数参数。bind接受一个函数(或函数对象等)作为参数,并产生一个函数对象。如下面两个例子:
int f(int i, char c, double d) { /* ... */ } int g(int) { /* */ } double g(double) { /* */ } int main() { // _1是占位符。使用时要加上using namespace std::placeholders; // 参数的绑定也称为局部套用(Currying) auto ff = bind(f, _1, 'c', 1.2); // 相当于f(7, 'c', 1.2); int x = ff(7); // 参数“反转” auto frev = bind(f, _3, _2, _1); frev(1.2, 'c', 1); // bind重载函数时 auto gg = bind((double(*)(double))g, _1); // 另一种形式:显式指定返回类型(在C++98中才能实现) auto f2 = bind<int>(f, 7, 'c', _1); return 0; }
struct st { int foo(int) { /* */ } int operator()(int x, int y) const { return x * y; }; }; int main() { // 创建函数对象 function<int(int x, int y)> f1 = st(); // 先创建st对象,再将其operator()函数赋值给f1。调用方式:f1(5, 3); vector<int> vec = {1, 3, 5, 7, 9}; // 将函数对象作为参数。累乘。2是起始值,结果为1890 cout << std::accumulate(vec.begin(), vec.end(), 2, f1) << endl; // 创建函数对象,“指向”成员函数,第一个参数为相应类对象的指针 function<int(st *, int)> f2; f2 = &st::foo; st s; int v = f2(&s, 5); // 调用s.foo(5) function<int(int)> ff = std::bind(f2, &s, _1); // bind的返回值可以赋值给函数对象 v = ff(5); // 调用s.foo(5) return 0; }
5、tuple:把各种不同类型元素组合起来的一种类型。它是pair类型的泛化。在概念上类似于C的struct,但它通过元素在tuple中的序号访问元素,而不是通过元素名。需要include <tuple>并使用std命名空间。
int main() { // 创建tuple tuple<const char *, int> tp1 = make_tuple("hello world", 11); // 获取元素 cout << get<0>(tp1) << "\t" << get<1>(tp1) << endl; int i = 0; // tie:将多个变量“捆绑(tie)”成一个tuple
// 如果只想获取tuple的部分元素,可以借助ignore tie(std::ignore, i) = tp1; cout << i << endl; pair<const char *, float> p1 = make_pair("Hello C++11", 1.2f); // tuple_cat:连结多个tuple(或pair) tuple<const char *, int, const char *, float, int> tp2 = tuple_cat(tp1, p1, tie(i)); // tuple_size:获取tuple的元素个数(维数)
cout << tuple_size<decltype(tp2)>::value << endl;
return 0; }
6、多线程相关
1)std::thread
2)std::atomic。需要包含<atomic>。另外,编译时需要加上-pthread选项。
atomic类型的对象“包含”了一个特定类型的值。atomic对象保证了从不同线程(同时)访问该值时不会引起数据竞争。以下是来自cplusplus的例子:
std::atomic<bool> ready(false); std::atomic<bool> winner(false); void count(int id) { while (!ready) {} // 等待开始“信号” for (int i = 0; i < 1000000; i++) {} // 每个线程都会计数到100w // exchange():(原子地)读取并替换atomic对象包含的值,返回替换前的值 // 如果某个线程的exchange操作返回false(在此之前还没有其他线程执行exchange操作),则它是第一个计数到100w的 if (!winner.exchange(true)) { std::cout << "thread #" << id << " won!\n"; } }; int main() { std::vector<std::thread> threads; for (int i = 1; i <= 10; i++) threads.push_back(std::thread(count, i)); ready = true; // 开始计数的“信号” for (auto &th : threads) th.join(); return 0; }
其他一些常用的函数:
store():修改atomic对象包含的值;load():读取atomic对象包含的值;fetch_add():(原子地)在atomic对象包含的值上做加法(read-modify-write),并返回操作前的值。
7、unordered_map
关联容器。和map类似,但其元素不是基于key或value排序,而是根据key的哈希值分配到内部哈希表的不同桶中。使用key访问元素的平均时间复杂度为常数。
#include <iostream> #include <string> #include <unordered_map> int main() { std::unordered_map<std::string, std::string> mymap = { {"house","maison"}, {"apple","pomme"}, {"tree","arbre"}, {"book","livre"}, {"door","porte"}, {"grapefruit","pamplemousse"} }; // 也可以这样遍历:for (auto &p : mymap) std::cout << "All elements: "; for (auto it = mymap.begin(); it != mymap.end(); it++) std::cout << "[" << it->first << ": " << it->second << "] "; std::cout << std::endl; // 此时mymap.bucket_count()为7 for (unsigned i = 0; i < mymap.bucket_count(); i++) { std::cout << "bucket #" << i << " has " << mymap.bucket_size(i) << " elements, they are: "; // begin()和end()的另一种用法 for (auto it = mymap.begin(i); it != mymap.end(i); it++) { std::cout << "[" << it -> first << ": " << it -> second << "] "; } std::cout << std::endl; } // 此时mymap.load_factor()为0.857143(即6/7) mymap.max_load_factor(0.5); // 由于此时load_factor > max_load_factor,故需要增加桶的数目,mymap.bucket_count()变为13 std::unordered_map<std::string, std::string>::hasher fn = mymap.hash_function(); // fn("this"): 2428694746313403453、fn("thin"): 18140520699013722149 return 0; }
[root@localhost ~]# ./a.out
All elements: [grapefruit: pamplemousse] [door: porte] [tree: arbre] [book: livre] [apple: pomme] [house: maison]
bucket #0 has 1 elements, they are: [tree: arbre]
bucket #1 has 2 elements, they are: [book: livre] [apple: pomme]
bucket #2 has 1 elements, they are: [door: porte]
bucket #3 has 0 elements, they are:
bucket #4 has 1 elements, they are: [house: maison]
bucket #5 has 0 elements, they are:
bucket #6 has 1 elements, they are: [grapefruit: pamplemousse]
常用函数说明:
load_factor():返回unordered_map容器当前的负载因数(load factor)。负载因数=容器中元素的个数/桶的数目,即平均每个桶的元素个数。它会影响哈希表中发生冲突的可能性。
max_load_factor():获取或设置load factor的最大值(默认为1.0)。
bucket_count():返回容器中桶的数目。桶的数目直接影响容器哈希表的负载因数,因而也影响冲突的可能性。当负载因数大于max_load_factor时,容器会自动增加桶的数目(以减小负载因数),此过程会对元素重新计算哈希值(rehash)。
bucket_size():返回桶中元素的个数(影响访问桶中特定元素的时间)。
size():返回容器中元素的个数。
bucket():通过key定位到元素在哪个桶中。
hash_function():获取容器使用的哈希函数对象。
8、final:用于修饰虚函数时,在派生类中将不可重写该函数;用于修饰类时,表示该类不可被继承。
struct Base { virtual void foo(); }; struct A : Base { void foo() final; // 将A::foo()声明为final void bar() final; // 出错:非虚函数不可声明为final }; struct B final : A // 将B声明为final { void foo() override; // 出错:因为A::foo()已经声明为final,不可被override }; struct C : B // 出错:B已经声明为final,不可被继承 { };
参考资料:
http://www.stroustrup.com/C++11FAQ.html
http://www.cplusplus.com
http://en.cppreference.com/w/cpp/language/final
http://segmentfault.com/a/1190000003004734?_ea=266751#articleHeader5
不断学习中。。。