现代c++学习笔记

目录

1、结构化绑定(c++17)

2、auto关键字

3、区间for迭代

4、委托构造(c++11)

5、lambda表达式

6、容器

std::array

std::forward_list

元组tuple

7、智能指针

std::share_ptr

std::unique_ptr

std::weak_ptr

多线程

创建线程

线程同步


1、结构化绑定(c++17)

返回多个返回值。

#include <iostream>
#include <tuple>

std::tuple<int, double, std::string> fun()
{
    return std::make_tuple(21, 2.1, "string");
}

int main()
{
    auto [x, y, z] = fun();
    std::cout << " x = " << x <<std::endl;
    std::cout << " y = " << y << std::endl;
    std::cout << " z = " << z << std::endl;

    return 0;
}

2、auto关键字

常用的使用地方是迭代器:

    #include <iostream>
    #include <vector>

    int main()
    {
        std::vector<int> vec = {1, 2, 3};

        for (auto it = vec.begin(); it != vec.end(); ++it)
        {
            std::cout << *it << std::endl;
        }

        return 0;
    }

其他常见的用法:

auto i = 5;              // i 被推导为 int
auto arr = new auto(10); // arr 被推导为 int *

从c++20起,auto可以用于修饰函数形参:

int add(auto x, auto y) 
{
    return x + y;
}

注意,auto不能用于推导数组类型。

3、区间for迭代

    #include <iostream>
    #include <vector>

    int main()
    {
        std::vector<int> vec = {1, 2, 3};

        for (auto k : vec)
        {
            std::cout << k << std::endl;
        }

        return 0;
    }

4、委托构造(c++11)

#include <iostream>
#include <vector>

class Base 
{
public:
    int value1;
    int value2;

public:
    Base() 
    {
        value1 = 1;
    }

    Base(int value) : Base() 
    {   
        // 委托 Base() 构造函数
        value2 = value;
    }
};

int main()
{
    Base b(2);
    std::cout << b.value1 << std::endl;
    std::cout << b.value2 << std::endl;

    return 0;
}

5、lambda表达式

格式如下:

capture:捕捉外部变量列表,可以是[],[=],[&],[]表示不捕捉任何外部变量,[=]表示以值的方式捕捉外部变量,当在lambda中不需要修改外部变量的时候,应该使用[=],顾名思义,[&]即以引用的方式捕捉外部变量,可以在lambda中修改外部变量。

parameters:形参,这个跟普通函数的形参是一样的。

mutable:修饰符,可以取消Lambda的常量属性,因为Lambda默认是const属性;multable仅仅是让Lamdba函数体修改值传递的变量,但是修改后并不会影响外部的变量。

return-type:返回值,同普通函数的返回值。
 

#include <iostream>


int main()
{ 
    auto func = [](int x, int y)->int{  
        return x + y;  
    };
 
    int sum = func(1, 2);  
    std::cout << sum << std::endl;  
 
    return 0;
}

6、容器

std::array

 与std::vector 不同,std::array 对象的大小是固定的,如果容器大小是固定的,那么可以优先考虑使用 std::array 容器。 另外由于 std::vector 是自动扩容的,当存入大量的数据后,并且对容器进行了删除操作, 容器并不会自动归还被删除元素相应的内存,这时候就需要手动运行 shrink_to_fit() 释放这部分内存。

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

std::forward_list

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

元组tuple

#include <iostream>
#include <tuple>

int main()
{
    //构造元组
    auto tup = std::make_tuple(21, "zhangsan");

    //获得元组某个位置的值
    std::cout << "age = " << std::get<0>(tup) << std::endl;
    std::cout << "name = " << std::get<1>(tup) << std::endl;

    //元组拆包
    int age;
    std::string name("");
    std::tie(age, name) = std::make_tuple(23, "lisi");
    std::cout << "age = " << age << std::endl;
    std::cout << "name = " << name << std::endl;

    return 0;
}

7、智能指针

std::share_ptr

//创建
auto ptr = std::make_shared<int>(10);

std::shared_ptr 可以通过 get() 方法来获取原始指针,通过 reset() 来减少一个引用计数, 并通过use_count()来查看一个对象的引用计数。

std::unique_ptr

std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象。

//创建
//make_unique 从 C++14 引入
std::unique_ptr<int> ptr = std::make_unique<int>(10);

由于是独占,就是不可复制。但是可以利用 std::move 将其转移给其他的 unique_ptr。

std::weak_ptr

std::weak_ptr是一种弱引用(相比较而言 std::shared_ptr 就是一种强引用)。

std::weak_ptr 没有 * 运算符和 -> 运算符,所以不能够对资源进行操作,它的唯一作用就是用于检查 std::shared_ptr 是否存在,其 expired() 方法能在资源未被释放时,会返回 false,否则返回 true

多线程

创建线程

#include <iostream>
#include <thread>

int main()
{
    std::thread t([]() {
        std::cout << "hello world" << std::endl;
    });

    t.join();

    return 0;
}

线程同步

std::mutex 是 C++11 中最基本的 mutex 类,通过实例化 std::mutex 可以创建互斥量, 而通过其成员函数 lock() 可以进行上锁,unlock() 可以进行解锁。 在实际编写代码的过程中,最好不去直接调用成员函数, 因为调用成员函数就需要在每个临界区的出口处调用 unlock(),当然还包括异常。 这时候 C++11 还为互斥量提供了一个 RAII 语法的模板类 std::lock_guard。 RAII 在不失代码简洁性的同时,很好的保证了代码的异常安全性。

#include <iostream>
#include <thread>
#include <mutex>

int v = 1;

void critical_section(int change_v) 
{
    static std::mutex mtx;
    std::lock_guard<std::mutex> lock(mtx);

    // 执行竞争操作
    v = change_v;

    // 离开此作用域后 mtx 会被释放
}

int main() 
{
    std::thread t1(critical_section, 2), t2(critical_section, 3);
    t1.join();
    t2.join();

    std::cout << v << std::endl;
    return 0;
}

由于 C++ 保证了所有栈对象在生命周期结束时会被销毁,所以这样的代码也是异常安全的。 无论 critical_section() 正常返回、还是在中途抛出异常,都会引发堆栈回退,也就自动调用了 unlock()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双鱼理

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值