首页 > 编程语言 >c++11特性汇总

c++11特性汇总

时间:2023-08-11 22:33:17浏览次数:48  
标签:11 std cout int auto 汇总 c++ shared ptr

c++11/14/17新特性

参考

C++11系列-什么是C++11

大丙教程

目录

1、关键字及新语法
  1.1、auto 关键字及用法
  1.2、nullptr 关键字及用法
  1.3、for 循环语法
2、智能指针内存管理
  2.1、std::shared_ptr
  2.2、std::weak_ptr
  2.3、std::unique_ptr
3、文件IO
  3.1、标准文件IO
  3.2、键盘外设输入
  3.3、控制台输入输出
4、稳定性和兼容性
  4.1、原始字面变量
  4.2、超长整形long long
  4.3、类成员的快速初始化
  4.4、final和override
  4.5、模板的优化
  4.6、数值类型和字符串之间的转化
  4.7、静态断言
  4.8、noexcept
5、c++ 多态与类继承关系
  5.1、动态多态与静态多态
  5.2、虚基类继承
6、其他
  6.1、std::function、std::bind封装可执行对象
  6.2、lamda表达式
  6.3、可变参数模板
  6.4、std::forward
  6.5、decltype
  6.6、lambda匿名函数
  6.7、多态(静态多态和动态多态)

1、关键字及新语法

1.1、auto关键字及用法

编译器根据上下文情况,确定auto变量的真正类型。

//c++14编译通过
auto AddTest(int a, int b) 
{
    return a + b;
}
//c++11形式
auto AddTest(int a,int b)->decltype(a+b)
{
    return a + b;
}

int main()
{
    auto index = 10;
    auto str = "abc";
    auto ret = AddTest(1,2);
    std::cout << "index:" << index << std::endl;
    std::cout << "str:" << str << std::endl;
    std::cout << "res:" << ret << std::endl;
}
  • c++11中直接用auto作为函数返回值会导致编译错误,需要利用decltype进行尾部类型推导
  • auto在C++14中可以作为函数的返回值
  • auto作为函数返回值时,只能用于定义函数,不能用于声明函数代码演示如下
// 声明函数
#pragma once
class Test
{
public:
    auto TestWork(int a ,int b); //编译不通过
};
// 定义函数
#pragma once
class Test
{
public:
    //c++14写法,省略decltype关键字进行尾部类型推导
    auto TestWork(int a, int b)
    {
        return a + b;
    }
};

auto关键字局限

  • auto不能作为函数的形参声明
  • auto作为函数返回值时不能用于函数声明,只能用于函数的定义
  • auto不能用于修饰非静态成员变量

1.2、nullptr关键字及用法

class Test
{
public:
    void TestWork(int index)
    {
        std::cout << "TestWork 1" << std::endl;
    }
    void TestWork(int * index)
    {
        std::cout << "TestWork 2" << std::endl;
    }
};

int main()
{
    Test test;
    test.TestWork(NULL);    // NULL被翻译成0       >>> TestWork 1
    test.TestWork(nullptr); // nullptr确定为 指针  >>> TestWork 2
}

1.3 范围for 配合auto

int main()
{
    int numbers[] = { 1,2,3,4,5 };
    std::cout << "numbers:" << std::endl;
    for (auto number : numbers)
    {
        std::cout << number << std::endl;
    }
}

2、多线程

C++11中,引入了boost库中的多线程部分内容,形成C++标准,
形成标准后的boost多线程编程部分接口基本没有变化,
这样方便了以前使用boost接口开发的使用者切换使用C++标准接口,
把容易把boost接口升级为C++接口。

2.1、std::thread

std::thread为C++11的线程类,使用方法和boost接口一样,非常方便,
同时,C++11的std::thread解决了boost::thread中构成参数限制的问题。
#include <thread>
void threadfun1()
{
    std::cout << "threadfun1 - 1\r\n" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));// 本线程休息1s
    std::cout << "threadfun1 - 2" << std::endl;
}

void threadfun2(int iParam, std::string sParam)
{
    std::cout << "threadfun2 - 1" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));// 本线程休息5s
    std::cout << "threadfun2 - 2" << std::endl;
}

int main()
{
    std::thread t1(threadfun1);// 线程绑定 需要执行的函数  打印 threadfun1 - 1
    std::thread t2(threadfun2, 10, "abc");           //  打印 threadfun2 - 1
    
    t1.join();// t1.join()会等待t1线程退出后才继续往下执行
                                                     //  打印 threadfun1 - 2
                                                     //  往下执行
    
    
    
    std::cout << "join" << std::endl;
    t2.detach();                // 执行的线程从线程对象中被分离,已不再被一个线程对象所表达,可以
    std::cout << "detach" << std::endl; // threadfun2 - 2 没有输出
    // detach字符输出后,主函数退出,threadfun2还未执行完成,但是在主线程退出后,t2的线程也被已经被强退出
}


2.2、std::atomic 原子数据类型。

从功能上看,简单地说,原子数据类型不会发生数据竞争,
能直接用在多线程中而不必我们用户对其进行添加互斥资源锁的类型。
从实现上,可以理解为这些原子类型内部自己加了锁。
// 使用10个线程,把std::atomic_int类型的变量iCount从100减到1。
#include <thread>
#include <atomic>
#include <stdio.h>
std::atomic_bool bIsReady = false;
std::atomic_int iCount = 100;
void threadfun1()
{
    if (!bIsReady) {
        std::this_thread::yield();
    }
    while (iCount > 0)
    {
        printf("iCount:%d\r\n", iCount--);
    }
}

int main()
{
    std::atomic_bool b;
    std::list<std::thread> lstThread;//线程列表 10个线程
    for (int i = 0; i < 10; ++i)
    {
        lstThread.push_back(std::thread(threadfun1));
    }
    for (auto& th : lstThread)
    {
        th.join();
    }
}

2.3、std::condition_variable

C++11中的std::condition_variable就像Linux下使用pthread_cond_wait和pthread_cond_signal一样,
可以让线程休眠,直到别唤醒,现在在从新执行。
线程等待在多线程编程中使用非常频繁,经常需要等待一些异步执行的条件的返回结果。
// webset address: http://www.cplusplus.com/reference/condition_variable/condition_variable/%20condition_variable
// condition_variable example
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {
    std::unique_lock<std::mutex> lck(mtx);
    while (!ready) cv.wait(lck);
    // ...
    std::cout << "thread " << id << '\n';
}

void go() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;
    cv.notify_all();
}

int main()
{
    std::thread threads[10];
    // spawn 10 threads:
    for (int i = 0; i<10; ++i)
        threads[i] = std::thread(print_id, i);

    std::cout << "10 threads ready to race...\n";
    go();                       // go!

    for (auto& th : threads) th.join();

    return 0;
}
// 在14行中调用cv.wait(lck)的时候,线程将进入休眠,在调用33行的go函数之前,
// 10个线程都处于休眠状态,当22行的cv.notify_all()运行后,14行的休眠将结束,继续往下运行

3、智能指针内存管理

简单地说,智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,
当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,
计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作。

如下图所示,简单话了一下指针、智能指针对象和计数器之间的关系:

#include <memory>
class Test
{
public:
    Test()
    {
        std::cout << "Test()" << std::endl;
    }
    ~Test()
    {
        std::cout << "~Test()" << std::endl;
    }
};
int main()
{
    std::shared_ptr<Test> p1 = std::make_shared<Test>();
    std::cout << "1 ref:" << p1.use_count() << std::endl;
    {
        std::shared_ptr<Test> p2 = p1;
        std::cout << "2 ref:" << p1.use_count() << std::endl;
    }
    std::cout << "3 ref:" << p1.use_count() << std::endl;
    return 0;
}

  1. std::make_shared封装了new方法,boost::make_shared之前的原则是既然释放资源delete由智能指针负责,那么应该把new封装起来,否则会让人觉得自己调用了new,但没有调用delete,似乎与谁申请,谁释放的原则不符。C++也沿用了这一做法
  2. 随着引用对象的增加std::shared_ptr p2 = p1,指针的引用计数有1变为2,当p2退出作用域后,p1的引用计数变回1,当main函数退出后,p1离开main函数的作用域,此时p1被销毁,当p1销毁时,检测到引用计数已经为1,就会在p1的析构函数中调用delete之前std::make_shared创建的指针

3.1、std::weak_ptr

std::weak_ptr网上很多人说其实是为了解决std::shared_ptr在相互引用的情况下出现的问题而存在的.

// A、std::shared_ptr相互引用的问题示例:=====

#include <memory>
class TestB;
class TestA
{
public:
    TestA()
    {
        std::cout << "TestA()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestB> test_ptr)
    {
        m_TestB_Ptr = test_ptr;
    }
    ~TestA()
    {
        std::cout << "~TestA()" << std::endl;
    }
private:
    std::shared_ptr<TestB> m_TestB_Ptr; //TestB的智能指针
}; 

class TestB
{
public:
    TestB()
    {
        std::cout << "TestB()" << std::endl;
    }

    void ReferTestB(std::shared_ptr<TestA> test_ptr)
    {
        m_TestA_Ptr = test_ptr;
    }
    ~TestB()
    {
        std::cout << "~TestB()" << std::endl;
    }
    std::shared_ptr<TestA> m_TestA_Ptr; //TestA的智能指针
};


int main()
{
    std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
    std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
    ptr_a->ReferTestB(ptr_b);
    ptr_b->ReferTestB(ptr_a);
    return 0;
}
/*我们创建了一个TestA和一个TestB的对象,但在整个main函数都运行完后,都没看到两个对象被析构,这是什么问题呢?

  原来,智能指针ptr_a中引用了ptr_b,同样ptr_b中也引用了ptr_a,在main函数退出前,
  ptr_a和ptr_b的引用计数均为2,退出main函数后,引用计数均变为1,也就是相互引用。

  这等效于说:
    ptr_a对ptr_b说,哎,我说ptr_b,我现在的条件是,你先释放我,我才能释放你,这是天生的,造物者决定的,改不了。
    ptr_b也对ptr_a说,我的条件也是一样,你先释放我,我才能释放你,怎么办?
  是吧,大家都没错,相互引用导致的问题就是释放条件的冲突,最终也可能导致内存泄漏。
  */

std::weak_ptr如何解决相互引用的问题我们在上面的代码基础上使用std::weak_ptr进行修改:

#include <memory>
class TestB;
class TestA
{
public:
    TestA()
    {
        std::cout << "TestA()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestB> test_ptr)
    {
        m_TestB_Ptr = test_ptr;
    }
    void TestWork()
    {
        std::cout << "~TestA::TestWork()" << std::endl;
    }
    ~TestA()
    {
        std::cout << "~TestA()" << std::endl;
    }
private:
    std::weak_ptr<TestB> m_TestB_Ptr;
};

class TestB
{
public:
    TestB()
    {
        std::cout << "TestB()" << std::endl;
    }

    void ReferTestB(std::shared_ptr<TestA> test_ptr)
    {
        m_TestA_Ptr = test_ptr;
    }
    void TestWork()
    {
        std::cout << "~TestB::TestWork()" << std::endl;
    }
    ~TestB()
    {
        std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock();
        tmp->TestWork();
        std::cout << "2 ref a:" << tmp.use_count() << std::endl;
        std::cout << "~TestB()" << std::endl;
    }
    std::weak_ptr<TestA> m_TestA_Ptr;
};


int main()
{
    std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
    std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
    ptr_a->ReferTestB(ptr_b);
    ptr_b->ReferTestB(ptr_a);
    std::cout << "1 ref a:" << ptr_a.use_count() << std::endl;
    std::cout << "1 ref b:" << ptr_a.use_count() << std::endl;
    return 0;
}
/*****************************************************************************/
1、所有的对象最后都能正常释放,不会存在上一个例子中的内存没有释放的问题。
2、ptr_a 和ptr_b在main函数中退出前,引用计数均为1,
   也就是说,在TestA和TestB中对std::weak_ptr的相互引用,不会导致计数的增加。
   在TestB析构函数中,调用std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock(),
   把std::weak_ptr类型转换成std::shared_ptr类型,然后对TestA对象进行调用。

5、其他特性

5.1、 std::functional 与std::bind封装可执行对象

#include <functional>
#include <iostream>
//
int main()
{
  
  return 0;
}

标签:11,std,cout,int,auto,汇总,c++,shared,ptr
From: https://www.cnblogs.com/dumoio/p/17624073.html

相关文章

  • C++快速排序
    快速排序介绍:基础思路:首先快速排序是由冒泡排序所改进的,都是通过多次比较和交换来实现排序,但快速排序是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,分别对这两部分记录继续进行排序,以达到整个序列有序。思路详解:(1)首先我们先设定......
  • 2023.8.11 模拟赛
    A询问\(L\lei,j\leR\),其中\(\gcd(i,j)\not=1,i,j\)的对数。莫反先求出\(gcd(i,j)\not=1\)的对数,然后再直接调和级数暴力删去\(i,j\)是倍数的对数即可。BP4334[COI2007]Policija考虑建立圆方树。圆方树是怎么样的呢?圆方树是对于每个点双,都建立一个方点,然后......
  • 代码随想录算法训练营第十六天| 104.二叉树的最大深度 111.二叉树的最小深度 222.
      104.二叉树的最大深度 (优先掌握递归)    卡哥建议:什么是深度,什么是高度,如何求深度,如何求高度,这里有关系到二叉树的遍历方式。大家要先看视频讲解,就知道以上我说的内容了,很多录友刷过这道题,但理解的还不够。   题目链接/文章讲解/视频讲解:https://programmerc......
  • 19.17RU安装问题汇总
    问题概述19.17RU安装问题汇总一、lib库被其他用户使用二、CRS-1159:Theclustercannotbesettorollingpatchmode三、NoreadorwritepermissiontoORACLE_HOME/.patch_storage四、Datapatch:couldn'topenencmapgbk.enc五、CRS-6706:OracleClusterwareReleasepatch......
  • [转]c++ function使用方法
    原帖:https://blog.csdn.net/myRealization/article/details/111189651 cppreference https://en.cppreference.com/w/cpp/utility/functional/functionboost源码剖析之:泛型函数指针类boost::functionhttps://blog.csdn.net/pongba/article/details/1560773c++模板偏特化 h......
  • 转载 | win11右键改为win10的bat命令(以及恢复方法bat)
    原文来自这里:https://blog.51cto.com/knifeedge/5340751 版权归:IT利刃出鞘  本质上就是写入注册表。 一、右键菜单改回Win10(展开)1.新建文件:win11右键展开.bat2.填写脚本内容regadd"HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\Inproc......
  • 2023.8.11 周五:保留小数点后几位
    1#include<iostream>2#include<iomanip>3intmain()4{5intn;6cin>>n;7doublePI=3.14159265358979;8cout<<setprecision(n)<<fixed<<PI<<endl;9return0;10}1......
  • 8.11
    #include<iostream>#include<vector>#include<cstdio>usingnamespacestd;constintN=1e5+10;vector<int>v[N];intn,vis[N];doublez,r,sum,ans;voiddfs(doublesum,intu){if(vis[u]){ans+=(sum*v[u][0]......
  • 闲话8.11
    晚上有雨,为了不断更把电脑拿宿舍了。上午依旧是劲爆模拟赛......
  • 8.11日
    "夏日里的微小快乐"在炎炎夏日,当阳光如金子般酒在大地上,生活中的微小快乐也仿佛被无限放大。我总是在这个季节找到最简单,最纯粹的快乐。可能是午后的冰淇淋,那一刻,甜蜜的滋味在舌尖上翻滚,所有的烦恼都随着炎热融化掉。可能是走在小巷,看着落日温柔的光线洒在老房子的砖墙上,或......