C++ 学习计划

May 21, 2018

0. 学习内容

目前准备在未来两个月中深入学习C++的一些重要的课题,在此制定一个阅读和学习计划。

C++博大精深、海纳百川,特别是在C++11之后的几代标准,使C++如何避免写出难以维护的代码,需要在长期的实践中不断提高自己的水平,丰富自己的知识。

这次的学习计划主要有如下内容:

  1. 现代C++的思想
  2. STL的使用
    • 序列式容器库
    • 关联式容器库
    • 算法库
    • allocator
  3. C++11 https://coolshell.cn/articles/5265.html
    • lambda表达式
    • 自动类型auto
    • nullptr
    • delete和default函数
    • 右值引用和move
    • 显式虚函数重载 override
    • 类型安全的枚举
    • C++ 11 STL 标准库 :线程、智能指针
  4. 模板

1. 现代C++的思想

1.1 基于堆栈的范围,而非堆或静态全局范围。

现代C++提倡

1.2 优先使用auto,而非显式类型名称。

使用自动类型推导主要有以下好处:

  1. 避免冗长的类型
  2. 防止未初始化的变量 int x1; // 有潜在的未初始化风险 auto x2; // 编译错误!必须有初始化物 auto x3 = 0; // 没问题,x的值初始化了
  3. 防止意外的类型转换 比如下面的这段代码:
    std::unordered_map<std::string, int> m;
    ...
    for (const std::pair<std::string, int>& p : m) {
        ...
    }

哈希表中的std::pair其实应该是std::pair<const std::string, int>,上面的写法编译器会对m中的每个对象做一次复制操作,生成一个p想要绑定的临时对象,在循环结束时这个临时对象将被析构一次,导致这个循环在性能上并不是最佳的。而这个问题可以用for(const auto &p :m)很轻易地来解决。

但是auto并不是完美的,有一部分情况下无法使用auto或者不适合使用auto

1.3 智能指针,而非原始指针。

1.4 std::string 和 std::wstring 类型,而非原始 char[] 数组。

1.5 标准模板库 (STL) 容器(例如 vector、list 和 map),而非原始数组或自定义容器。

1.6 STL 算法,而非手动编码的算法。

1.7 异常,可报告和处理错误条件。

1.8 使用 STL std::atomic<>(请参见 ),而非其他线程间通信机制的无锁线程间通信。

1.9 内联 lambda 函数,而非单独实现的小函数。

1.10 基于范围的 for 循环,编写以 for ( for-range-declaration : expression ) 形式使用数组、STL 容器和 Windows 运行时集合的更可靠循环。

传统的C++代码片段示例

    // circle and shape are user-defined types  
    circle* p = new circle( 42 );   
    vector<shape*> v = load_shapes();  
      
    for( vector<circle*>::iterator i = v.begin(); i != v.end(); ++i ) {  
        if( *i && **i == *p )  
            cout << **i <<  is a match\n;  
    }  
      
    for( vector<circle*>::iterator i = v.begin();  
            i != v.end(); ++i ) {  
        delete *i; // not exception safe  
    }  
      
    delete p;  
    #include <memory>  
    #include <vector>  
    // ...  
    // circle and shape are user-defined types  
    auto p = make_shared<circle>( 42 );  
    vector<shared_ptr<shape>> v = load_shapes();  
      
    for_each( begin(v), end(v), [&]( const shared_ptr<shape>& s ) {  
        if( s && *s == *p )  
            cout << *s << " is a match\n";  
    } );  

2. 使用Eclipse Memory Analyzer分析内存

首先下载它:www.eclipse.org/mat/downloads.php 然后安装它:这里不啰嗦了

以下用mat代替Eclipse Memory Analyzer

2.1 转换格式

2.2 查找GC Root

3. 找到泄露原因

4. LeakCanary不是万能的