C++11新增的重要的知识点讲解和测试

这里主要是对C++11比较重要的一些的东西的使用进行讲解和如何去使用。
C++11

// C++11.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <vector>
#include <complex>      //复数
#include <set>
using namespace std;

//(2).自动推到函数
double f() { return 1.0; }//定义了函数
auto d = f();//自动推到函数
//1.tuto自动类型的推导
void test01()
{
    //1.自动推到基础类型
    auto i = 42;//自动推到变量

    //3.对复杂类型的推到,迭代器
    vector<string>v;
    v.push_back("123456");
    auto pos = v.begin();

    //4.推导lamuda表达式
    auto l = [](int x)->bool {
        cout << "输入的参数为" << x << endl;
        cout << "lamuda表达式" << endl;
        return true;
    };


    {
        cout << i << endl;

        cout << d << endl;

        cout << *pos << endl;//如果容器中的数据为空,引用会报错

        cout << l(1) << endl;
    }
    //注意:类中的成员变量式不能够进行类型推导的,因为类只是声明,初始化才赋值
    //类中不能使用auto
}


//2.一致性初始化和初值列
class Test02
{
public:
    //一致性初始化,就是使用大括号进行初始化{}
    int values[3]{ 1,2,3 };
    std::vector<int>v{ 2,3,4,5,8 };
    std::vector<std::string>cities{
        "Berlin","New York","London","Cairo","Cologne"
    };
    std::complex<double>c{ 4.0,3.0 };

    //初值列,即没有指定的值的变量,自动赋值为0或者nullptr
    int i;
    int j{};
    int* p;
    int* q{};
    void test() {
    cout << "i的值:" << i << endl;
    cout << "j的值:" << j << endl;
    cout << "p的值:" << p << endl;
    cout << "q的值:" << q << endl;
    }

    //窄化:精度降低或者是数值类型不匹配,对大括号来说都是不可以的
    //int x3{ 5.0 };//错误
    char c1{ 7 };
    //char c2{ 99999 };
    std::vector<int>v1{ 1,2,3,4,5 };
    //std::vector<int>v2{1,2.3,4,5.6}

    //用户的自定义的类型的初值列class template::initializer_list<>
    void print(std::initializer_list<int>vals)
    {
        for (auto p = vals.begin(); p != vals.end(); ++p) {
            cout << *p << "\n";
        }
    }
};
void test02()
{
    Test02 test;
    test.test();
    test.print({ 12,3,5,7,11,13,17 });
}

//3.增加类似for_each()的循环
void test03()
{
    //打印集合中的元素
    for (int i : {2, 3, 5, 7, 9, 13, 17, 19})
    {
        cout << i << endl;
    }

    //容器中每个数乘以3
    std::vector<double>vec{ 2.3,5.5,2.6,4.2,3.6 };
    for (auto& elem : vec)
    {
        elem *= 3;
    }
}
template<class T>
void printElements(const T& coll)
{
    for (const auto& elem : coll)
    {
        std::cout << elem << std::endl;
    }

    //等同于
    //for (auto pos = coll.begin(); pos != coll.end(); pos++)
    //{
    //    std::cout << elem << std::endl;
    //}
}

//4.move搬迁语句,避免非必要的拷贝和临时对象
template<class X>
void createAndInsert(std::set<X>& coll)
{
    X x;
    coll.insert(x);
    coll.insert(std::move(x));
}

//5新式的字符串字面常量Raw String
void test05()
{
    //Raw String
    string a = "\\\\n";//表示两个反斜线和一个n
    string b = R"(\\n)";

    //如果要在R中出现括号),使用定义符,16个基本的字符,不可以含有反斜线,空格,和小括号
    string c = R"nc(\dfg  dfj\fd p90()(000))()())nc";

    //编码的字符串,使用不同的编码完成国际化
    cout << u8"hello" << endl;//utf8,字符类型是const char
    cout << u"hello" << endl;//string literal,类型char16_t的字符
    cout << U"hello" << endl;//string literal,类型char32_t的字符
    cout << L"hello" << endl;//wide string literal,类型wchar_t的字符
}

//6关键字noexcept,用来指明某个函数无法或不打算抛出异常
void foo() noexcept;

//7关键字constexpr,用来让表达式核定于编译期
constexpr int square(int x)
{
    return x * x;
}
void test07()
{
    float a[square(9)];
    cout << sizeof(a) / sizeof(float) << endl;
}

//9Lambda;语法[](){}(),指定返回值的类型[](参数)->类型 {};(就等于函数里面嵌套函数了)
void test09()
{
    [] {cout << "hello lambda" << endl; }();//直接调用
    //把他转递给对象
    auto l = [] {cout << "hello lambda2" << endl; };
    l();

    char16_t q='a';//两个字节的char
    cout << sizeof(q) << endl;
}

int main()
{
    test09();
}


已经分小点测试了,需要学习的直接拿走,自己动手实践一下就能够加深印象和理解的,希望都不要觉得C++难。

拓展:
前几天,写了C++的中简单的使用的一些知识点,也测了好多小的点,今天有空,把没有写完的扩展完成了。

新增:
智能指针,我们都知道,C++的神奇之处就在于指针的使用,如果没有了指针就没有了灵魂了,但是对于初学者来说,指针真的是一个痛点,特别是内存的问题就是难点的问题了,在堆上的内存还是需要我们程序员去释放内存的,如果忘记的释放,那么我们的程序就会崩掉。

智能指针的用处:引入了智能指针,就是可以不用我们再去释放在堆上开辟的空间了。

//智能指针
//需要的头文件#include <memory> 
void test10()
{
    //智能指针的构造(怎么样去弄一个智能指针出来)
    //1.直接使用构造函数
    shared_ptr<int>ptr(new int(10));//在堆上开辟了int类型*ptr=10
    cout << "指针的地址"<<ptr << endl;//指针的地址
    cout <<"指针对应的值"<< *ptr << endl;//指针对应的值
    *ptr = 100;//使用指针修改数据
    cout << *ptr << endl;

    //2.使用make  make_shared<int>(100)
    shared_ptr<int>ptr1 = make_shared<int>(20);
    shared_ptr<int>ptr2{new int(101)};//结合使用C++的{}一致性初始化
    cout <<"结合使用C++的{}一致性初始化ptr2的值:"<< *ptr2 << endl;
    cout << " ptr1的指针的地址:" << ptr1 << endl;
    cout <<"get()返回的指针的地址:"<< ptr1.get() << endl;
    cout << " ptr1的值:" << *ptr1 << endl;
    cout << " ptr1的值:" << *ptr1.get() << endl;

    //3.使用已经存在的指针拷贝
    {
        shared_ptr<int>ptr3 = ptr2;
        cout << "引用计数:" << ptr2.use_count() << endl;//是多个指针指向了同一个内存空间
        //ptr2和ptr3指向了同一个空间,引用计数为2
    }
    cout << "引用计数:" << ptr2.use_count() << endl;//是多个指针指向了同一个内存空间
    //ptr3作用域结束,ptr3没有了,但内存空间没有释放,引用计数为1
}
void test11()
{
    //已经知道了,可以使用智能指针指向一个int类型,其他类型类似,
    //但这里想深入理解如果类型是指针会怎样
    int a = 10;
    shared_ptr<int*>ptr(new int* (&a));
    cout << *ptr << endl;
    cout << **ptr << endl; 
    //可以看到,我们使用了指针指向了我们在堆上开辟的指针类型int*的
    //跟一个二级指针类似
    
    int b = 20;
    int* bptr = &b;
    shared_ptr<int**>ptr1(new int** (&bptr));
    cout << *ptr1 << endl;
    cout << **ptr1 << endl;
    cout << ***ptr1 << endl;
    //如果类型是 二级指针,那么智能指向二级指针后,就是一个三级指针
}

class A
{
public:
    A(int age)
    {
        m_age = age;
        cout << "construct A(int)" << age << endl;
    }
    A(char* name)
    {
        memset(m_name, 0x00, sizeof(m_name));
        strcpy(m_name, name);
        cout << "construct A(char*)" << name << endl;
    }
    ~A()
    {
        cout << "destruct A" << endl;
    }
private:
    int m_age;
    char m_name[16];
};

void test12()
{
    shared_ptr<A>ptr = make_shared<A>(50);
    char a[] = "zhangsan";
    shared_ptr<A>ptr1 = make_shared<A>(a);
}

void test13()
{
    //reset()函数的作用:改变指针的指向
    shared_ptr<int>ptr = make_shared<int>(100);
    shared_ptr<int>prt1 = ptr;
    cout << "引用计数:" << ptr.use_count() << endl;
    ptr.reset(new int);
    cout << "引用计数" << ptr.use_count() << endl;
}

//unique_ptr
void test14()
{
    unique_ptr<A>ptr(new A(50));
    //unique_ptr<A>ptr1 = ptr;错误,unique_ptr的引用计数不能超过1
    unique_ptr<A>ptr1=move(ptr);//ptr不再指向A了,由ptr1拥有

    unique_ptr<A>ptr2 = make_unique<A>(100);
}

//数组对象的
void test15()
{

    shared_ptr<A>ptr(new A[5]{20,20,20,20,20}, [](A* p) {
        delete[]p;//析构数组
        });
}

//指针的使用
void test17()
{
    //智能指针如何去使用
    //使用shared_ptr创建数组
    shared_ptr<int>ptr(new int[10]);
    shared_ptr<char>ptr1 = make_shared<char>();

    int* pp= ptr.get();//获取指针的资源之后就可以像使用指针一样去使用
    int* p = pp;
    for (int i = 0; i < 10; i++)
    {
        *pp = 10;
        pp++;
    }
    pp = p;
    for (int i = 0; i < 10; i++,pp++)
    {
        cout << (*pp) << endl;
    }
}

c++11新增的重要的知识点已经讲得差不多了,今天我们还得深入的理解C++的Lambda表达式的使用,因为对于C++的回调函数来说Lambda表达式式非常好用的,尤其是使用STL的时候,我们很多时候要提供函数来实现自己想要的功能的。

C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:

[capture](parameters) mutable ->return-type
{
statement
}

[函数对象参数](操作符重载函数参数)mutable ->返回值{函数体}

有了这个结构体,我们说一下如何使用。
首先说一下这个Lambda表达式必须有的结构

[](){}

就是这三个括号,其他的东西可根据需要增加。

【】括号中可以增加什么
① 函数对象参数;
[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
 空。没有使用任何函数对象参数。
 =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
 &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
 this。函数体内可以使用Lambda所在类中的成员变量。
 a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
 &a。将a按引用进行传递。
 a, &b。将a按值进行传递,b按引用进行传递。
 =,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
 &, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

class B
{
public:
    int a;
    int b;
    int c;

    //4.this
    void test()
    {
        //函数嵌套lambda,lambda作用域下是不能够访问类中成员的
        //auto fun4 = []() {cout << a << endl; };
        auto fun4_1 = [=]() {cout << a << endl; };
        auto fun4_2 = [this]() {cout << b << endl; };
        auto fun4_3 = [&]() {cout << c << endl; };
        fun4_1();
        fun4_2();
        fun4_3();
    }

    B() { a = 10; b = 20; c = 30; };
    ~B() {};
};
//测试[]中的参数
void test16()
{
    //1.空
    auto fun1 = []() {return 1+2; };//返回1+2
    cout <<"1.空:"<< fun1() << endl;

    //2.=(值传递)
    int a = 10;
    //auto fun2 = []() {cout << a << endl; }//报错,如果[]为空,a在lambda中是不知道
    cout <<"a的内存地址:"<< &a << endl;
    
    auto fun2 = [=]() {
        cout << "2.=:"<<endl;
        cout<<"a的值:" << a << endl; 
        cout << "[=]的传递a的地址:" << &a << endl;//与a的地址不同
        //a = 20;报错,因为值传递是没有办法去修改a的值的
        int b = a * 2; //那值传递有什么用
        cout <<"b的值:" <<b << endl; };
    fun2();

    //3.&(引用传递)
    auto fun3 = [&]() {
        cout << "3.&" << endl;
        cout<<"[&]的传递a的地址:"<<&a << endl;//与a的地址相同
        a = 20; //修改a的值
        cout <<"[&]的传递,修改a的值:"<< a << endl;
        };
    fun3();
    cout << "a最后的值:" << a << endl;

    //4.this
    B classB;
    auto fun4 = [&classB]() {classB.test(); };
    //fun4();
    //classB.test();

    int b = 20;
    auto fun5 = [&]() {fun4(); };
    fun5();

}

② 操作符重载函数参数;
标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

//测试()中的参数
void test18()
{
    vector<int>ve;
    for (int i = 0; i < 10; i++)
    {
        ve.push_back(i);
    }
    //查找容器中的满足大于5的
    auto l=find_if(ve.begin(), ve.end(), [](int v) {
        return v > 5;
        });
    cout << *l << endl;
}

③ 可修改标示符;
mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。

//测试mutable
void test19()
{
    int a = 10;
    auto l = [a]() {
        //报错a = 100;
    };
    auto ll = [a]()mutable {
        a = 100;
    };
    //修改的只是拷贝,原先的值是没有修改的
    cout << a << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值