美文网首页
C++11新特性

C++11新特性

作者: 上官宏竹 | 来源:发表于2021-06-07 17:20 被阅读0次

    std::this_thread::yield()

    看代码如下:

    while(true) {
        if(pool.try_get_work()) {
            // do work
        }
        else {
            std::this_thread::yield(); // other threads can push work to the queue now
        }
    }
    

    (1) std::this_thread::yield(); 是将当前线程所抢到的CPU”时间片A”让渡给其他线程(其他线程会争抢”时间片A”,
    注意: 此时”当前线程”不参与争抢)。
    等到其他线程使用完”时间片A”后, 再由操作系统调度, 当前线程再和其他线程一起开始抢CPU时间片.
    (2) 如果将 std::this_thread::yield();上述语句修改为: return; ,则将未使用完的CPU”时间片A”还给操作系统, 再由操作系统调度, 当前线程和其他线程一起开始抢CPU时间片。
    std::this_thread::yield() 是让线程让渡出自己的CPU时间片(给其他线程使用)
    std::this_thread::sleep_for() 是线程根据某种需要, 需要等待若干时间.

    noexcept

    Lambda表达式

    C++ 11 Lambda表达式

    函数对象

    函数对象(function object),也称仿函数(functor),通常来讲, 是指重载了函数调用操作符operator()的类所实例化的对象,该对象的行为类似于函数。

    class Minus
    {
    public:
        int operator()(int iLeft, int iRight)
        {
            return iLeft - iRight;
        }
    };
    
    int main()
    {
        Minus o_minus;
        int i_result = o_minus(10, 5);
    
        return 0;
    }
    
    函数对象和函数指针性能比较

    函数对象相比函数指针,性能更高。因为调用operator()实质上是调用这个类成员的成员函数,而这个成员函数默认是inline的。但函数指针就是普通的调用函数,效率低。(这里要知道inline内联函数的优势)
    参考Effective STL,条款46:C++的sort使用默认的函数对象总是比C里的qsort效率高。

    智能指针

    1. 永远不要将new用在shared_ptr构造函数参数列表(shared_ptr<int> x = shared_ptr<int>(new int);)以外的地方。
    2. unique_ptr不支持普通的拷贝和赋值操作,不能用在STL标准容器中。
    3. auto_ptr不支持拷贝和赋值操作,不能用在STL标准容器中。

    参考:shared_ptr和unique_ptr区别和联系
    参考:智能指针的原理及实现
    参考:浅谈shared_ptr及shared_ptr涉及到的循环引用问题
    参考:C++ 智能指针(unique_ptr, shared_ptr)的源码分析

    1. unique_ptr用法

    unique_ptr <>不可复制,只能移动。

    std::unique_ptr<int> ptr1;  // 空的unique_ptr对象
    std::unique_ptr<Task> taskPtr(new Task(23));    // 使用原始指针创建
    std::unique_ptr<Task> taskPtr2 = new Task();   // 编译错误。不能通过赋值创建
    
    std::unique_ptr<Task> taskPtr3 = std::move(taskPtr);    // 传递所有权,taskPtr为空
    
    //释放来自原始指针的对象的所有权
    Task * ptr = taskPtr3.release();
    

    2. shared_ptr用法

    // 初始化
    shared_ptr<int> x = shared_ptr<int>(new int); // 这个方法有缺陷,下面我会说
    shared_ptr<int> y = make_shared<int>();
    shared_ptr<Resource> obj = make_shared<Resource>(arg1, arg2); // arg1, arg2是Resource构造函数的参数
    // 赋值
    shared_ptr<int> z = x; // 此时z和x共享同一个引用计数器
    // 像普通指针一样使用
    int val = *x;
    assert (x == z);
    assert (y != z);
    assert (x != nullptr);
    obj->someMethod();
    // 其它辅助操作
    x.swap(z); // 交换两个shared_ptr管理的裸指针(当然,包含它们的引用计数)
    obj.reset(); // 重置该shared_ptr(引用计数减1)
    

    shared_ptr使用
    shared_ptr 原理及事故

    错误用法1:多个无关的shared_ptr管理同一裸指针

    {
        int *a = new int;
        std::shared_ptr<int> p1(a);
        std::shared_ptr<int> p2(a);
        // shared_ptr<int> x = shared_ptr<int>(new int);  // 正确的用法,有缺陷
        std::cout << "p1 use_count:" << p1.use_count() << " p2 use_count:" << p2.use_count() << std::endl;  // 输出 1 1
    }
    

    p1和p2同时管理同一裸指针a,此时的p1和p2有着完全独立的两个引用计数器,计数器都为1(初始化p2时,用的是裸指针a,于是我们没有任何办法获取p1的引用计数!),于是,上面的代码会导致a被delete两次,分别由p1和p2的析构导致。
    为了避免这种情况的发生,我们永远不要将new用在shared_ptr构造函数参数列表(shared_ptr<int> x = shared_ptr<int>(new int);)以外的地方,或者干脆不用new,改用make_shared。

    错误用法2:循环引用。weak_ptr 解决shared_ptr循环引用问题

    循环引用问题:

    class B;
    class A {
    public:
        A() { cout << "A struct" << endl; }
        ~A() { cout << "~A" << endl; }
        void setB(shared_ptr<B> _b) { m_b = _b; }
    private:
        shared_ptr<B> m_b;
    };
    
    class B {
    public:
        B(shared_ptr<A> _a) : m_a(_a) { cout << "B struct" << endl; }   
        ~B() { cout << "~B" << endl; }
    private:
        shared_ptr<A> m_a;
    };
    
    void test1()
    {
        // 没有循环引用
        // 虽然a的引用计数会达到2,但在a/b实例析构时,分别会减去引用计数,而最终完成内存释放
        cout << "============ test1 start =============" << endl;
        shared_ptr<A> a = make_shared<A>(); // a
        cout << "a.use_count: " << a.use_count() << endl;
        shared_ptr<B> b = make_shared<B>(a);
        cout << "b.use_count: " << b.use_count() << endl;
        cout << "a.use_count: " << a.use_count() << endl;
        cout << "============ test1 end  =============" << endl;
    }
    
    void test2()
    {
        // 循环引用
        cout << "============ test2 start =============" << endl;
        shared_ptr<A> a = make_shared<A>();
        cout << "a.use_count: " << a.use_count() << endl;
        shared_ptr<B> b = make_shared<B>(a);
        cout << "b.use_count: " << b.use_count() << endl;
        cout << "a.use_count: " << a.use_count() << endl;
        a->setB(b);
        cout << "b.use_count: " << b.use_count() << endl;
        cout << "============ test2 end  =============" << endl;
    }
    
    int main()
    {
        test1();
        test2();
    }
    
    输出: image.png

    3 weak_ptr用法

    用一个shared_ptr初始化weak_ptr

    std::shared_ptr<int> sharedP(new int(5));
    std::weak_ptr<int> weakP = sharedP;
    

    weakP.lock()后会改变shared_ptr的引用计数(+1)

    // weak_ptr不会改变shared_ptr,但是会和shared_ptr的引用保持一致
    std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 1, 1
    
    // weakP.lock()后会改变shared_ptr的引用计数(+1)
    std::shared_ptr<int> sharedP2 = weakP.lock();
    std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 2, 2
    

    weak_ptr没有重载*,->操作符,因此不可直接通过weak_ptr使用对象,只能通过lock()使用shared_ptr来操作

    // 编译报错,weak_ptr没有重载*,->操作符,因此不可直接通过weak_ptr使用对象,只能通过lock()使用shared_ptr来操作
    //std::cout << " number is " << *weakP << std::endl;
    
    sharedP.reset();
    std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 0, 1
    
    if (weakP.expired()) {
        std::cout << "shared_ptr object has been destory" << std::endl;  // 不会进入
    }
    
    std::shared_ptr<int> sharedP3 = weakP.lock();
    std::cout << "sharedP3 use_count:" << sharedP3.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;// 2, 2
    std::cout << "number is " << *sharedP3 << std::endl;    // 5
    

    C++ 11 创建和使用共享 weak_ptr

    4. enable_shared_from_this

    当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

    struct Good : std::enable_shared_from_this<Good> // 注意:继承
    {
    public:
        std::shared_ptr<Good> getptr() {
            return shared_from_this();
        }
        ~Good() { std::cout << "Good::~Good() called" << std::endl; }
    };
     
    int main()
    {
        // 大括号用于限制作用域,这样智能指针就能在system("pause")之前析构
        {
            std::shared_ptr<Good> gp1(new Good());
            std::shared_ptr<Good> gp2 = gp1->getptr();
            // 打印gp1和gp2的引用计数
            std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;
            std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;
        }
        system("pause");
    }
    

    C++11新特性之十:enable_shared_from_this

    匿名空间

    当定义一个命名空间时,可以忽略这个命名空间的名称:

         namespce {
             char c;
             int i;
             double d;
         }
    

    编译器在内部会为这个命名空间生成一个唯一的名字,而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于:

         namespace __UNIQUE_NAME_ {
             char c;
             int i;
             double d;
         }
         using namespace __UNIQUE_NAME_;
    

    在匿名命名空间中声明的名称也将被编译器转换,与编译器为这个匿名命名空间生成的唯一内部名称(即这里的__UNIQUE_NAME_)绑定在一起。还有一点很重要,就是这些名称具有internal链接属性,这和声明为static的全局名称的链接属性是相同的,即名称的作用域被限制在当前文件中,无法通过在另外的文件中使用extern声明来进行链接。如果不提倡使用全局static声明一个名称拥有internal链接属性,则匿名命名空间可以作为一种更好的达到相同效果的方法。C++ 新的标准中提倡使用匿名命名空间,而不推荐使用static,因为static用在不同的地方,涵义不同,容易造成混淆.另外,static不能修饰class。

    相关文章

      网友评论

          本文标题:C++11新特性

          本文链接:https://www.haomeiwen.com/subject/ndbxlltx.html