c++11新特性

NULL和nullptr

nullptr的出现以避免将空指针NULL转为整数0带来的错误.

auto和decltype

都是从表达式的类型推断出要定义的变量类型,但是decltype但是不想用该表达式的值初始化变量(初始化可以用auto)

花括号初始化

int values[]{1, 2, 3};
vector<int> v{2, 3, 5, 7, 11, 13, 17};
vector<string> cities{"Berlin", "New York", "London", "Braunschweig" "Cairo", "Cologne"};
complex<double> c{4.0, 3.0}; 	// 等价于 c(4.0, 3.0)

功能:
1.值初始化,未定义的基础数据类型的变量值设为0(或nullptr).

int i;		// i has undefined value
int j{};	// j is initialized by 0
int* p;		// P has undefined value
int* q{};	// q is initialized by nullptr

2.当自动类型转换可能使变量降低精度时报错.

int x1(5.3);		// OK, but OUCH: xl becomes 5
int x2 = 5.3;		// OK, but OUCH: x2 becomes 5
int x3{5.0};		// ERROR: narrowing
int x4 = {5.3};		// ERROR: narrowing
char c1{7};			// OK: even though 7 is an int, this is not narrowing
char c2{99999};		// ERROR: narrowing (if 9999 doesn 'fut into a char)
std::vector<int> v1{1, 2, 4, 5};		// OK
std::vector<int> v2{1, 2.3, 4, 5.6};	// ERROR: narrowing

底层依赖于模板类initializer_list,该类封装了一个array<T,n>.调用函数时该array内的元素可被编译器分解逐一传递给函数.若函数参数是initializer_list,则传入的数据不会被拆解.

void print(std::initializer_list<int> vals) {
    for (auto p = vals.begin(); p != vals.end(); ++p) { //a list of values
        std::cout << *p << endl;
    }
}

print({12, 3, 5, 7, 11, 13, 17}); 		// pass a list of values to print()

若函数同时有接收多个参数的重载版本和接收initializer list的重载版本,则优先调用接收initializer list的重载版本.

class P {
public:
    // 有两个重载版本的构造函数,uniform initialization时优先调用接收initializer list的重载版本
    P(int a, int b) {
        cout << "P(int, int), a=" << a << ", b=" << b << endl;
    }

    P(initializer_list<int> initlist) {
        cout << "P(initializer list<int>), values= ";
        for (auto i : initlist)
            cout << i << ' ';
        cout << endl;
    }
};

P p(77, 5);		// P(int, int), a=77, b=5
P q{77, 5};		// P(initializer list<int>), values= 77 5
P r{77, 5, 42}; // P(initializer list<int>), values= 77 5 42
P s = {77, 5};	// P(initializer list<int>), values= 77 5

STL中的大部分容器和算法相关函数均有接收initializer list的重载版本

=default、=delete

使用=default使得编译给类加上默认的构造函数、析构函数、拷贝构造函数、拷贝赋值函数、移动构造函数等.
=delete(或简写为=0)表示删除该函数,使得该类不具有对应的构造、析构、拷贝构造、拷贝赋值、析构等功能.

noexcept

修饰函数代表不会抛出异常

 MyString &operator=(MyString &&str) noexcept {
        ++MAsgn;
        if (this != &str) {
            if (_data) delete _data;
            _len = str._len;
            _data = str._data; //MOVE!
            str._len = 0;
            str._data = nullptr; // 将传入对象的_data指针设为nullptr,防止析构函数多次delete同一根指针
        }
        return *this;
    }

override

重写的话,父类的成员函数为virtual修饰,且子类函数与父类函数完全一致

使用关键字override好处:当子类漏写了虚函数重写的某个苛刻条件,也可以通过编译器的报错,快速改正错误

class Base {
public:
    virtual void mf1() const;
    virtual void mf2(int x);
    virtual void mf3() &;
    void mf4() const;    // is not declared virtual in Base
};
class Derived: public Base {
public:
    virtual void mf1() override;
    virtual void mf2(unsigned int x) override;
    virtual void mf3() && override;
    virtual void mf4() const override;
};

所以override加不加不影响子类重写父类

final

修饰类,该类不会被继承,修饰函数,该函数不会被重写
在这里插入图片描述

右值引用

用途:加快容器操作

右值是临时对象,如数值1,函数返回值等

注意:右值不能放等号左边,只能放等号右边

当右值出现在赋值运算符=的右侧时,我们认为对其资源进行偷取/搬移(move)而非拷贝(copy)是合理的,依次:

1.必须有语法让我们在调用端告诉编译器这是一个右值.

2.必须有语法让我们在被调用端写出一个专门处理右值的移动赋值函数.

专门处理右值的函数使用value_type&&声明参数:

iterator insert(const_iterator __position, const value_type& __x);
iterator insert(const_iterator __position, value_type&& __x);

在这里插入图片描述

我们是insert是先去调用一下中介的一个函数,可能出现改变变量的可变性和左值右值等性质,

使用std::forward()函数可以完美转交变量,不改变其可变性和左值右值等性质.

// 函数process的两个重载版本,分别处理参数是左值和右值的情况
void process(int &i) {
    cout << "process(int&):" << i << endl;
}
void process(int &&i) {
    cout << "process(int&&):" << i << endl;
}

// 中间转交函数forward使用std::forward()转交变量
void forward(int &&i) {
    cout << "forward(int&&):" << i << ", ";
    process(std::forward<int>(i));
}

forward(2);           	// forward(int&&):2, process(int&&):2	(临时变量作左值传给forward函数,forward函数体内使用std::forward函数包装变量,保留其作为右值的性质)
forward(std::move(a));  // forward(int&&):0, process(int&&):0	(临时变量作左值传给forward函数,forward函数体内使用std::forward函数包装变量,保留其作为右值的性质)

std::move()函数可将左值转为右值来传递

接下来就是我们的移动构造函数移动赋值函数

#include <cstring>

class MyString {
public:
    static size_t DCtor;    // 累计默认构造函数调用次数
    static size_t Ctor;     // 累计构造函数调用次数
    static size_t CCtor;    // 累计拷贝构造函数调用次数
    static size_t CAsgn;    // 累计拷贝赋值函数调用次数
    static size_t MCtor;    // 累计移动构造函数调用次数
    static size_t MAsgn;    // 累计移动赋值函数调用次数
    static size_t Dtor;     // 累计析构函数调用次数
private:
    char *_data;
    size_t _len;

    void _init_data(const char *s) {
        _data = new char[_len + 1];
        memcpy(_data, s, _len);
        _data[_len] = '\0';
    }

public:
    // 默认构造函数
    MyString() : _data(nullptr), _len(0) { ++DCtor; }

	// 构造函数
    MyString(const char *p) : _len(strlen(p)) {
        ++Ctor;
        _init_data(p);
    }

    // 拷贝构造函数
    MyString(const MyString &str) : _len(str._len) {
        ++CCtor;
        _init_data(str._data);
    }

    // 拷贝赋值函数
    MyString &operator=(const MyString &str) {
        ++CAsgn;
        if (this != &str) {
            if (_data) delete _data;

            _len = str._len;
            _init_data(str._data); //COPY!
        }
        return *this;

    }

    // 移动构造函数
    MyString(MyString &&str) noexcept : _data(str._data), _len(str._len) {
        ++MCtor;
        str._len = 0;
        str._data = nullptr; 	// 将传入对象的_data指针设为nullptr,防止析构函数多次delete同一根指针
    }

	// 移动赋值函数
    MyString &operator=(MyString &&str) noexcept {
        ++MAsgn;
        if (this != &str) {
            if (_data) delete _data;
            _len = str._len;
            _data = str._data; //MOVE!
            str._len = 0;
            str._data = nullptr; // 将传入对象的_data指针设为nullptr,防止析构函数多次delete同一根指针
        }
        return *this;
    }

    //dtor
    virtual ~MyString() {
        ++Dtor;
        if (_data)
            delete _data;
    }
};

size_t MyString::DCtor = 0;
size_t MyString::Ctor = 0;
size_t MyString::CCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MCtor = 0;
size_t MyString::MAsgn = 0;
size_t MyString::Dtor = 0;

其实就是移动构造函数就是让当前指针指向临时指针的同一块空间,然后将临时指针置空,防止析构函数delete释放同一块内存空间,移动赋值函数就只是加了检测自我赋值的一个操作罢了

特别注意:移动构造函数和移动赋值函数参数列表之后必须加noexcept关键字,否则不会调用

容器测试:

1.在插入元素部分,只有vector容器的速度受元素是否movable影响大,这是因为只有容器vector在增长过程中会发生复制.

2.对于所有容器,其移动构造函数都远快于其拷贝构造函数,容器vector的移动复制函数仅仅发生了指针的交换,未发生元素的复制.

lambda表达式

写了一个函数但没有名字

[] {
    std::cout << "hello lambda" << std::endl;
};

// 用作变量
auto l = [] {
    std::cout << "hello lambda" << std::endl;
};
l();

// 直接执行
[] {
    std::cout << "hello lambda" << std::endl;
}();

在这里插入图片描述

int id = 0;
auto f = [id]() mutable {
    std::cout << "id:" << id << std::endl;
    ++id;
};
id = 42;
f();							// id:0
f();							// id:1
f();							// id:2
std::cout << id << std::endl;	// 42

lambda函数使用时相当于仿函数(functor)[…]中传入的对象相当于为仿函数的成员变量.

class Functor {
    private:
    int id; // copy of outside id
    public:
    void operator()() {
        std::cout << "id: " << id << std::endl;
        ++id; // OK
    }
};
Functor f;

一般用于当函数功能比较简单,比如修改sort函数排序规则及其它函数

// lambda函数充当predict谓词
vector<int> vi{5, 28, 50, 83, 70, 590, 245, 59, 24};
int x = 30;
int y = 100;
remove_if(vi.begin(), vi.end(),
          	[x, y](int n) { return x < n && n < y; });

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++11引入了许多新特性,其中包括线程池的实现。在引用中的代码中,ZERO_ThreadPool类封装了线程池的功能。线程池的原理是通过维护一个线程队列和一个任务队列来实现的。 在初始化阶段,通过调用init函数来初始化线程池。该函数会创建指定数量的线程,并将其保存在threads_队列中。如果线程池已经被初始化过,则直接返回false。 在启动线程池后,调用start函数。该函数会循环创建指定数量的线程,并将它们放入threads_队列中。每个线程都会调用run函数来执行任务。 当调用exec函数时,会将任务添加到tasks_队列中。其中,std::bind用于绑定一个成员函数和其参数,以及占位符std::placeholders::_1表示传入的参数。 在waitForAllDone函数中,会判断atomic_是否为0且tasks_是否为空。如果是,则表示所有任务已经执行完毕,线程池可以退出。 线程池的stop函数用于停止线程池的运行。它会遍历threads_队列,并调用每个线程的join函数,等待线程执行完毕后再返回。 以上就是C++11新特性线程池的基本原理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于C++11新特性手写线程池实现](https://blog.csdn.net/m0_70418130/article/details/126805390)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值