• 转载 C++11新特性学习


    自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性。近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料。因为自己有C++98的基础,所以从C++98过渡到C++11并不算特别吃力,读了一些书籍后,算是对C++11有了个比较基础的理解,感觉程序员还是要经常保持新语言新特性的更新,现在 C++ 标准都出到C++17了!这篇文章就是对C++11一些常用新特性的一些总结,以C++98C++11在语法上的差异来突出C++11新特性的非凡优势。

    一、新语法

    1.自动类型推导auto

    auto的自动推导,用于从初始化表达式中推断出变量的数据类型。

    
    //C++98
    int a = 10;
    string s = "abc";
    float b = 10.0;
    vector<int> c;
    vector<vector<int> > d;
    map<int, string> m;
    m[1] = "aaa";
    map<int, string>::iterator it = m.begin();
    

    //C++11
    auto a1 = 10; //a1为int
    auto s1 = "abc"; //s1为string
    auto b1 = b;
    auto c1 = c;
    auto d1 = d;
    auto e1 = 'a';
    int* x = &a1;
    auto d1 = x;
    auto m1 = m.begin();
    auto x=1,y=2; //ok
    auto i=1.j=3.14; //compile error

    double a2 = 3.144;
    const auto a3 = a2; //const double
    auto a4 = a2; //double
    volatile int c2 = 3;
    auto c3 = c2; //int

    2.萃取类型decltype

    decltype可以通过一个变量或表达式得到类型。

    #include <iostream>
    #include <vector>
    

    using namespace std;

    int add(int a)
    {
    return ++a;
    }

    void fun(int a)
    {
    cout << "call function: [int] " << endl;
    }

    void fun(int a)
    {
    cout << "call function: [int
    ] " << endl;
    }

    int main()
    {
    //C++11
    int aa = 10;
    decltype(aa) bb = 11;
    string ss = "hello intel";
    decltype(ss) ss1 = "hello";
    const vector<int> vec(1);
    decltype(vec[0]) cc = 1;
    decltype(0) dd = vec[0]; //dd是int类型
    decltype(add(1)) ee; //int
    int a[5];
    decltype(a) ff; //int[5]
    //decltype(fun) gg; 无法通过编译,是个重载函数

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    3.nullptr

    空指针标识符nullptr是一个表示空指针的标识,他不是一个整数,这是与我们常用的NULL宏的区别。NULL只是一个定义为常整数0的宏,而nullptr是C++11的一个关键字,一个內建的标识符。

    #include <iostream>
    #include <vector>
    

    using namespace std;

    void fun(int a)
    {
    cout << "call function: [int] " << endl;
    }

    void fun(int a)
    {
    cout << "call function: [int
    ] " << endl;
    }

    int main()
    {
    //C++11
    fun(NULL); //call function: [int]
    fun(nullptr); //call function: [int*]

    <span class="hljs-keyword">int</span>* p = <span class="hljs-literal">NULL</span>;
    fun(p);  <span class="hljs-comment">//call function: [int*]</span>
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    4.区间迭代range for

    C++98C++11在使用语法上的差异如下:

    #include <iostream>
    #include <vector>
    

    using namespace std;

    int main()
    {
    //C++98
    vector<int> vec(8, 1);
    cout << "C++98 range for:" << endl;
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
    cout << *it << endl;
    }

    <span class="hljs-comment">//C++11</span>
    <span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"C++11 range for:"</span> &lt;&lt; <span class="hljs-built_in">endl</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> d : vec)
    {
        <span class="hljs-built_in">cout</span> &lt;&lt; d &lt;&lt; <span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    值得指出的是,是否能够使用基于范围的for循环,必须依赖一些条件。首先,就是for循环迭代的范围是可确定的。对于类来说,如果该类有begin和end函数,那么for_each之间就是for循环迭代的范围。对于数组而言,就是数组的第一个和最后一个元素间的范围。其次,基于范围的for循环还要求迭代的对象实现+ + 和==等操作符。对于STL中的容器,如string、array、map等使用起来是不会有问题的。下面是C++11操作vector和数组的实践:

    #include <iostream>
    #include <vector>
    

    using namespace std;

    int main()
    {
    vector<int> vec(8, 1);

    <span class="hljs-comment">//C++11</span>
    <span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"C++11 value range for:"</span> &lt;&lt; <span class="hljs-built_in">endl</span>;
    <span class="hljs-comment">/*d非引用,修改d不会影响vector里的值*/</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> d : vec)   <span class="hljs-comment">//d中存储的是vec中的值</span>
    {
        d = <span class="hljs-number">2</span>;
    }
    
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> d : vec)   
    {
        <span class="hljs-built_in">cout</span> &lt;&lt; d &lt;&lt; <span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"C++11 reference range for:"</span> &lt;&lt; <span class="hljs-built_in">endl</span>;
    <span class="hljs-comment">/*当迭代变量d为引用时,vector里的值可以被修改*/</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> &amp;d : vec)  
    {
        d = <span class="hljs-number">2</span>;
    }
    
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> d : vec)   
    {
        <span class="hljs-built_in">cout</span> &lt;&lt; d &lt;&lt; <span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-comment">//数组for_each</span>
    <span class="hljs-keyword">char</span> arr[] = {<span class="hljs-string">'a'</span>,<span class="hljs-string">'b'</span>,<span class="hljs-string">'c'</span>,<span class="hljs-string">'d'</span>};
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> &amp;d : arr)
    {
        d -= <span class="hljs-number">32</span>;
    }
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> d : arr)
    {
        <span class="hljs-built_in">cout</span> &lt;&lt; d &lt;&lt; <span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-comment">//遍历二维数组,注意迭代变量row必须为引用。如果你想用 range for 的方法,来遍历更高维的数组 (dim &gt; 2),那么你只需要:除了最内层循环之外,其他所有外层循环都加入 '&amp;' 即可。</span>
    <span class="hljs-keyword">int</span> array2[<span class="hljs-number">5</span>][<span class="hljs-number">5</span>] = {<span class="hljs-number">0</span>};
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> &amp;row : array2)
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> col : row)
            <span class="hljs-built_in">cout</span> &lt;&lt; col &lt;&lt; <span class="hljs-built_in">endl</span>;
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    5.返回类型后置语法

    先看下面这个例子,编译器在推导decltype(t1+t2)时表达式中t1和t2都未声明,所以编译失败。

    
    #include <iostream>
    #include <vector>
    

    using namespace std;

    template<class T1, class T2>
    decltype(t1 + t2) sum(T1 t1, T2 t2)
    {

    return t1 + t2;
    }

    int main()
    {
    auto total = sum(1, 2);
    cout << total << endl;
    return 0;
    }

    所以C++11引入新语法,即把函数的返回值移至参数声明之后,复合符号->decltype(t1+t2)被称为追踪返回类型。而原本的函数返回值由auto占据。

    #include <iostream>
    #include <vector>
    

    using namespace std;

    template<class T1, class T2>
    auto sum(T1 t1, T2 t2) ->decltype(t1+t2)
    {

    return t1 + t2;
    }

    int main()
    {
    auto total = sum(1, 2);
    cout << total << endl;
    return 0;
    }

    6.final和override

    struct B
    {
        virtual void f1(int) const;
        virtual void f2();
        void f3();
    };
    

    struct D1 : public B
    {
    void f1(int) const override; //ok
    void f2(int) override; //error,B中没有形如f2(int)的函数
    void f3() override; //error,f3不是虚函数
    void f4() override; //error,B中无f4函数
    };

    struct D2 : public B
    {
    void f1(int) const final; //不许后续的其他类覆盖
    };

    struct D3 :public D2
    {
    void f2();
    void f1(int) const; //error,final函数不可覆盖
    };

    final还可以用于防止继承的发生

    class NoDerived final
    {
    

    };

    class Bad :NoDerived //NoDerived不可做基类
    {

    };

    class Base
    {

    };

    class Last final :Base
    {

    };

    class Bad2 :Last //Last不可做基类
    {

    };

    7.=default和=delete

    对于 C++ 的类,如果程序员没有为其定义特殊成员函数,那么在需要用到某个特殊成员函数的时候,编译器会隐式的自动生成一个默认的特殊成员函数,比如拷贝构造函数,或者拷贝赋值操作符。

    C++11允许我们使用=default来要求编译器生成一个默认构造函数,也允许我们使用=delete来告诉编译器不要为我们生成某个默认函数

    class B
    {
        B() = default; //显示声明使用默认构造函数
        B(const B&) = delete; //禁止使用类对象之间的拷贝
        ~B() = default;  //显示声明使用默认析构函数
        B& operator=(const B&) = delete;  //禁止使用类对象之间的赋值
        B(int a);  
    };

    8.lambda表达式

    简单来说,Lambda函数也就是一个函数(匿名函数),它的语法定义如下:

    [capture](parameters) mutable ->return-type{statement}
    1. [=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
    2. [&,a,this]表示以值传递的方式捕捉变量a和类的this指针,引用传递方式捕捉其它所有变量。
    #include <iostream>
    

    using namespace std;

    int main()
    {
    auto f = {cout << "hello world!" << endl; };
    f(); //hello world!

    <span class="hljs-keyword">int</span> a = <span class="hljs-number">123</span>;
    <span class="hljs-keyword">auto</span> f1 = [a] { <span class="hljs-built_in">cout</span> &lt;&lt; a &lt;&lt; <span class="hljs-built_in">endl</span>; };
    f1();  <span class="hljs-comment">//123</span>
    
    <span class="hljs-keyword">auto</span> f2 = [&amp;a] {<span class="hljs-built_in">cout</span> &lt;&lt; a &lt;&lt; <span class="hljs-built_in">endl</span>; };
    a = <span class="hljs-number">789</span>;
    f2();  <span class="hljs-comment">//789</span>
    
    <span class="hljs-comment">//隐式捕获:让编译器根据函数体中的代码来推断需要捕获哪些变量</span>
    <span class="hljs-keyword">auto</span> f3 = [=] {<span class="hljs-built_in">cout</span> &lt;&lt; a &lt;&lt; <span class="hljs-built_in">endl</span>; };
    f3();  <span class="hljs-comment">//789</span>
    
    <span class="hljs-keyword">auto</span> f4 = [&amp;] {<span class="hljs-built_in">cout</span> &lt;&lt; a &lt;&lt; <span class="hljs-built_in">endl</span>; };
    a = <span class="hljs-number">990</span>;
    f4();  <span class="hljs-comment">//990</span>
    
    <span class="hljs-keyword">auto</span> f5 = [](<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b)-&gt;<span class="hljs-keyword">int</span> {<span class="hljs-keyword">return</span> a + b; };
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d
    "</span>, f5(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>));  <span class="hljs-comment">//3</span>
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    lambda表达式在C++下的应用,排序

    #include <stdio.h>
    #include <algorithm>
    #include <vector>
    

    using namespace std;

    void print(char arr[], int len)
    {
    for (int i = 0; i < len; i++)
    {
    printf("%d ", arr[i]);
    }
    printf(" ");
    }

    bool cmp(char a, char b)
    {
    if (a > b)
    return true;
    else
    return false;
    }

    int main()
    {
    //c++98
    char arr1[] = { 2,5,2,1,5,89,36,22,89 };
    int len = sizeof(arr1) / sizeof(char);
    sort(arr1, arr1 + len, cmp);
    print(arr1, len);

    <span class="hljs-comment">//c++11</span>
    <span class="hljs-keyword">char</span> arr2[] = { <span class="hljs-number">2</span>,<span class="hljs-number">5</span>,<span class="hljs-number">2</span>,<span class="hljs-number">1</span>,<span class="hljs-number">5</span>,<span class="hljs-number">89</span>,<span class="hljs-number">36</span>,<span class="hljs-number">22</span>,<span class="hljs-number">89</span> };
    <span class="hljs-keyword">int</span> len2 = <span class="hljs-keyword">sizeof</span>(arr2) / <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">char</span>);
    sort(arr2, arr2 + len2, [](<span class="hljs-keyword">char</span> a, <span class="hljs-keyword">char</span> b)-&gt;<span class="hljs-keyword">bool</span> {<span class="hljs-keyword">return</span> a &gt; b; });
    print(arr2, len2);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    9.std::move

    std::move是为性能而生,通过std::move,可以避免不必要的拷贝操作。std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。

    #include <iostream>
    #include <utility>
    #include <vector>
    #include <string>
    int main()
    {
        std::string str = "Hello";
        std::vector<std::string> v;
        //调用常规的拷贝构造函数,新建字符数组,拷贝数据
        v.push_back(str);
        std::cout << "After copy, str is "" << str << ""
    "; //After move, str is "Hello"
        //调用移动构造函数,掏空str,掏空后,最好不要使用str
        v.push_back(std::move(str));
        std::cout << "After move, str is "" << str << ""
    ";   //After move, str is ""
        std::cout << "The contents of the vector are "" << v[0]
            << "", "" << v[1] << ""
    ";   //The contents of the vector are "Hello", "Hello"
    }

    二、STL新内容

    1.std::array

    1. 使用 std::array保存在栈内存中,相比堆内存中的 std::vector,我们就能够灵活的访问这里面的元素,从而获得更高的性能;同时正式由于其堆内存存储的特性,有些时候我们还需要自己负责释放这些资源。

    2. 使用std::array能够让代码变得更加现代,且封装了一些操作函数,同时还能够友好的使用标准库中的容器算法等等,比如 std::sort。

    std::array 会在编译时创建一个固定大小的数组,std::array 不能够被隐式的转换成指针,使用 std::array 很简单,只需指定其类型和大小即可:

    #include <stdio.h>
    #include <algorithm>
    #include <array>
    

    void foo(int* p)
    {

    }

    int main()
    {
    std::array<int, 4> arr = {4,3,1,2};

    foo(&amp;arr[<span class="hljs-number">0</span>]);  <span class="hljs-comment">//OK</span>
    foo(arr.data());  <span class="hljs-comment">//OK</span>
    <span class="hljs-comment">//foo(arr);  //wrong</span>
    <span class="hljs-built_in">std</span>::sort(arr.begin(), arr.end());  <span class="hljs-comment">//排序</span>
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    2.std::forward_list

    std::forward_list 使用单向链表进行实现,提供了 O(1) 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 size() 方法的容器。当不需要双向迭代时,具有比 std::list 更高的空间利用率。

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <forward_list>
    

    int main()
    {
    std::forward_list<int> list1 = { 1, 2, 3, 4 };

    <span class="hljs-comment">//从前面向foo1容器中添加数据,注意不支持push_back</span>
    list1.pop_front();  <span class="hljs-comment">//删除链表第一个元素</span>
    list1.remove(<span class="hljs-number">3</span>);   <span class="hljs-comment">//删除链表值为3的节点</span>
    list1.push_front(<span class="hljs-number">2</span>);
    list1.push_front(<span class="hljs-number">1</span>);
    list1.push_front(<span class="hljs-number">14</span>);
    list1.push_front(<span class="hljs-number">17</span>);
    
    list1.sort();
    
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> &amp;n : list1)
    {
        <span class="hljs-keyword">if</span> (n == <span class="hljs-number">17</span>)
            n = <span class="hljs-number">19</span>;
    }
    
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> &amp;n : list1)
    {
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; n &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//1 2 2 4 14 19</span>
    }
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    3.std::unordered_map和std::unordered_set

    无序容器中的元素是不进行排序的,内部通过 Hash 表实现,插入和搜索元素的平均复杂度为 O(constant),在不关心容器内部元素顺序时,能够获得显著的性能提升。

    C++11 引入了两组无序容器:std::unordered_map/std::unordered_multimap 和 std::unordered_set/std::unordered_multiset。

    下面给出unordered_map和unordered_set的使用方法。

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <unordered_map>
    #include <unordered_set>
    

    void foo(int* p)
    {

    }

    int main()
    {
    //unordered_map usage
    std::unordered_map<std::string, int> um = { {"2",2},{"1",1},{"3",3} };

    <span class="hljs-comment">//遍历</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> &amp;n : um)
    {
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"key:"</span> &lt;&lt; n.first &lt;&lt; <span class="hljs-string">"  value:"</span> &lt;&lt; n.second &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"value:"</span> &lt;&lt; um[<span class="hljs-string">"1"</span>] &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;
    
    
    <span class="hljs-comment">//unordered_set usage</span>
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">unordered_set</span>&lt;<span class="hljs-keyword">int</span>&gt; us = { <span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">1</span>};
    
    <span class="hljs-comment">//遍历</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> &amp;n : us)
    {
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"value:"</span> &lt;&lt; n &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;
    }
    
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"value:"</span> &lt;&lt; us.count(<span class="hljs-number">9</span>) &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>; <span class="hljs-comment">//判断一个数是否在集合内,1存在0不存在</span>
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"value:"</span> &lt;&lt; *us.find(<span class="hljs-number">1</span>) &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//查找一个特定的数是否在集合内,找到就返回该数的迭代器位置</span>
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    三、智能指针

    1. std::shared_ptr

    shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。

    #include <stdio.h>
    #include <memory>
    #include <iostream>
    

    int main()
    {
    //auto ptr = std::make_shared<int>(10);
    std::shared_ptr<int> ptr(new int(10));
    std::shared_ptr<int> ptrC(ptr);

    <span class="hljs-keyword">auto</span> ptr2 = ptr;
    
    {
        <span class="hljs-keyword">auto</span> ptr3 = ptr2;
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer1.use_count() = "</span> &lt;&lt; ptr.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//4</span>
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer2.use_count() = "</span> &lt;&lt; ptr2.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//4</span>
    }
    
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer1.use_count() = "</span> &lt;&lt; ptr.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//3</span>
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer2.use_count() = "</span> &lt;&lt; ptr2.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//3</span>
    
    <span class="hljs-keyword">int</span> *p = ptr.get(); <span class="hljs-comment">//获取原始指针</span>
    
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer1.use_count() = "</span> &lt;&lt; ptr.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//3</span>
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"pointer2.use_count() = "</span> &lt;&lt; ptr2.use_count() &lt;&lt; <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;  <span class="hljs-comment">//3</span>
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    3 2. std::unique_ptr

    std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证代码的安全:

    #include <stdio.h>
    #include <memory>
    #include <iostream>
    

    int main()
    {
    std::unique_ptr<int> ptr(new int(10));
    //auto ptr2 = ptr; //非法

    <span class="hljs-comment">//虽说unique_ptr是不可复制的,但我们可以使用std::move将其独占权转移到其他的unique_ptr</span>
    auto ptr2(std::move(ptr));
    std::cout &lt;&lt; *ptr2 &lt;&lt; std::endl;
    
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    3. std::weak_ptr

    先观察下面的代码,如果我们在类father中使用的是shared_ptr son的话,father和son的实例并没有顺利回收,输出如下:

    father !
    son !

    以上问题就是shared_ptr的环形引用问题。为了避免shared_ptr的环形引用问题,需要引入一个弱引用weak_ptr, weak_ptr是为了配合shared_ptr而引入的一种智能指针,弱引用不会引起引用计数增加,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况.

    #include <iostream>
    #include <memory>
    using namespace std;
    

    class father;
    class son;

    class father {
    public:
    father() {
    cout << "father !" << endl;
    }
    ~father() {
    cout << "~~~~~father !" << endl;
    }
    void setSon(shared_ptr<son> s) {
    son = s;
    }
    private:
    //shared_ptr<son> son;
    weak_ptr<son> son; // 用weak_ptr来替换
    };

    class son {
    public:
    son() {
    cout << "son !" << endl;
    }
    ~son() {
    cout << "~~~~~~son !" << endl;
    }
    void setFather(shared_ptr<father> f) {
    father = f;
    }
    private:
    shared_ptr<father> father;
    };

    void test() {
    shared_ptr<father> f(new father());
    shared_ptr<son> s(new son());
    f->setSon(s);
    s->setFather(f);
    }

    int main()
    {
    test();
    return 0;
    }

    输出:

    father !
    son !
    ~~~~~~son !
    ~~~~~father !
    无欲则刚 关心则乱
  • 相关阅读:
    tomcat配置和原理(转)
    maven install、maven clean、project clean
    spring注解的(List&Map)特殊注入功能
    React父子组件传值
    使用Ant Design的Upload上传删除预览照片,以及上传图片状态一直处于uploading的解决方法。
    使用react-redux
    URLSearchParams生成和解析URL或者参数字符串
    Ant Design的Table组件去除“取消排序”选项
    React Hooks的useState和useEffect
    webpack配置alias简化相对路径
  • 原文地址:https://www.cnblogs.com/xjyxp/p/11101908.html
Copyright © 2020-2023  润新知