c++11新特性总结

1.2、constexpr:

近似const, 可以修饰变量,也可以修饰函数

const int global = 100;
int main () 
{
    int temp = 100;
    constexpr int a = 1; //right
    constexpr int b = global; //right
    constexpr int c = temp; //wrong
}

既可以赋值字面常量也可以赋值const变量
重点:constexpr修饰的函数,生效于编译时而不是运行时, 重点应用于修饰函数使其在编译期大幅度被解释
被constexpr修饰的函数,无论是普通函数,还是类成员函数,必须是编译器可计算得到结果,即字面常量,不可是运行时才能获取的内容

constexpr int calc_in_compile_0 ()
{
    return 100;
}

constexpr int calc_in_compile_1 (int a)
{
    return a * 100;
}

constexpr int calc_in_compile_2 (int b, int c)
{
    return c * calc_in_compile_1(b);
}

int main()
{
    std::cout<< calc_in_compile_0() << std::endl;
    constexpr int a = 1;
    std::cout<< calc_in_compile_1(a) << std::endl;
    std::cout<< calc_in_compile_2(a, calc_in_compile_1(a)) << std::endl;

    return 0;
}
//100
//100
//10000
//代替了"const _max = INT_MAX"
static constexpr int max () 
{
    return INT_MAX;
}
static constexpr int min () 
{
    return INT_MIN;
}

constexpr int _max = max(), _min = min();
class Calc
{
    double a_;
public:
    /*构造函数在这里,必须用constexpr修饰,因为类成员函数是用constexpr修饰的*/
    constexpr Calc(double a):a_(a) {}

    constexpr double GetAbs() const
    {
        return std::abs(a_);
    }
    constexpr double GetSquare() const
    {
        return a_ * a_;
    }
};

int main()
{
    constexpr Calc calc(5.1);
    constexpr double _fabs = calc.GetAbs();
    ///_fabs = 10.0;
    std::cout << "fabs: " << _fabs <<std::endl;
    double _abs = calc.GetAbs();
    std::cout << "abs: " << _abs <<std::endl;
    _abs = 10.0;
    std::cout << "abs: " << _abs <<std::endl;
    double _square = calc.GetSquare();
    std::cout << "square: " << _square <<std::endl;
    _square = 10.0;
    std::cout << "square: " << _square <<std::endl;
}

1.3、using取代typedef:

typedef double db; //c99
using db = double; //c++11

typedef void(*function)(int, int);//c99,函数指针类型定义
using function = void(*)(int, int);//c++11,函数指针类型定义

using kvpairs = std::map<std::string, std::string>; //c++11
using CompareOperator = std::function<int(kvpairs &, kvpairs &)>; //c++11
template<class T> using twins = std::pair<T, T>; //更广泛的还可以用于模板

1.4、auto & decltype:

int main()
{
    //auto让编译器通过初始值来推算变量的类型。当然,其定义的变量必须要有初始值
    auto a = 1;
    //decltype(变量)可以获取变量的类型
    decltype(a) b = 2;

    //注意下,decltype((a))的结果是引用,此时创建新的变量就将会报错,或者说:
    //int &b = a;
    //decltype(b) c;//也报错,因为b是a的引用,decltype(b)就会报错,效果同decltype((a))
}

1.5、字符串和数值类型的转换
以前的atoi、itoa等等成为历史
to_string:itoa成为历史
stoi、stol、stoul、stoll、stoull、stof、stod、stold:atoX成为历史

1.5、random_device
生成随机数,免去了以前需要自行调用srand初始化种子的步骤

#include<random>
int main()
{
    std::random_device rd;
    uint32_t randint = rd();
}

1.6、std::ref和std::cref
分别对应变量的引用和const引用,主要用于作为c++11函数式编程时传递的参数
1.7、std::chrono时间相关
1.8、原子变量
std::atomic<XXX>
用于多线程资源互斥操作,属c++11重大提升,多线程原子操作简单了许多
事实上基于c++11实现的无锁队列,让boost::lockfree无锁队列也将成为历史
1.9、正则表达式std::regex
恶心的C正则(regex.h)和boost正则成为历史
1.10、编译期断言static_assert
static_assert是用于涉及模板的assert,编译期就能发现不满足的情况,无需等到运行时
如下最后一个被注掉的static_assert如果放开,则无法通过编译。

template<class T>
class C
{
    T data1_;
    int data2_;
public:
    C(T data1, int data2):data1_(data1), data2_(data2)
    {
        static_assert(sizeof(T) >= 4, "sizeof(T) is not larger than 4");
        static_assert(data2_ >= 10, "condition must could be calced in compling!");
    }
};

int main()
{
    C<double> c(1.1, 1);
    return 0;
}

2、容器
2.1、tuple 和 花括号初始化
元组的出现,和python拉齐了,c++也实现了函数可以多个返回值
2.2、hash正式进入stl
unordered_map、unordered_set、unordered_multimap、unordered_multiset。extstl扩展方式的使用hash成为历史。
2.3、emplace:
对于标准类型没有变化,如std:;vector<int>,push_back和emplace_back效果一样
2.4、shrink_to_fit
能减少不少无意义的内存空间占用
push、insert这类操作会触发容器的capacity,即预留内存的扩大,实际开发时往往这些扩大的区域并没有用途    

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    v.push_back(1);
    std::cout << "before shrink_to_fit: " << v.capacity() << std::endl;
    v.shrink_to_fit();
    std::cout << "after shrink_to_fit: " << v.capacity() << std::endl;
}
//before shrink_to_fit: 10
//after shrink_to_fit: 6

3、对于类
3.1、构造函数
1、default
2、delete关键字禁止拷贝构造、禁止赋值构造、禁止自定义参数的构造函数
注意析构函数不可由delete修饰
c++11以前的方式,是把需要禁止的构造函数,放在private里使外部无法调用;
3、委托构造函数
4、移动构造函数:
属于c++11的右值引用的衍生效果之一,首先描述右值引用std::move
std::move主要解决拷贝性能问题
类似于python的深拷贝和浅拷贝, python中的对象赋值和copy.copy都是浅拷贝, 赋值的都是对象的引用, copy.deepcopy则是深拷贝
直接定位到实际应用上(程序中尽量不要出现"int &&a = 1"这样的东西,炫技容易搞出错误)
用途为:
1、减少内存复制成本
2、将不再需要的变量,取消它对原先持有变量(内存)的持有(修改)权限
移动构造函数,最大的用途避免同一份内存数据的不必要的变成两份甚至多份、过程中的变量传递导致的内存复制,另外解除了栈变量对内存的引用;
例三:c++11风格的新老容器的数据移交:
如果一个老容器如vector容器oldv,需要将其内部数据复制给新容器如vector容器newv,且老容器后面无用,数据量很大;
那么c++11的std::make_move_iterator将派上用场,它可以将一个普通迭代器,如oldv.begin(),转化为"move式迭代器",配合std::copy,将老容器内全部数据的引用,move给新容器同时取消老容器对数据的持有权。这就是c++11风格的高速数据拷贝方式。

int main()
{
    std::vector<std::string> oldv = {"123", "456", "789"};
    std::vector<std::string> newv(oldv.size());

    for (auto &i: oldv)
    {
        std::cout << i << "\t";
    }
    std::cout << std::endl;
    //c++11做法,move引用
    std::copy(std::make_move_iterator(oldv.begin()), std::make_move_iterator(oldv.end()), newv.begin());
    //std::copy(oldv.begin(), oldv.end(), newv.begin());    //传统做法,复制
    for (auto &i: oldv)
    {
        std::cout << i << "\t";
    }
    std::cout << std::endl;
    for (auto &i: newv)
    {
        std::cout << i << "\t";
    }
    std::cout << std::endl;
}
//第一次打印:老容器正常打印
//第二次打印:老容器无法打印了
//第三次打印:新容器正常打印
//123	456	789

//123	456	789

5、继承构造函数
近似于委托构造函数原理,如下:

struct A 
{
    int a;
    A(int _a):a(_a + 100){}
};
struct B : public A 
{
    int b;
    B(int _b):A(_b), b(_b + 10000){}
};

3.2、override和final
作用于虚函数,更多的作用是:显式的标识是否应该多态继承或不应该
1、override:子类用override修饰其虚函数,表示要多态继承基类的虚函数。不可以修饰非虚函数。写在函数后面
virtual bool FullMergeV2() const override {}
2、final:基类用final修饰其虚函数,其子类不可以多态继承该虚函数

class father
{
public:
    int a_;
    int GetA() {return a_;}
    virtual void SetA(int a) final {a_ = a;}
public:
    father(int a):a_(a) {}
};

class Son: public father
{
    int b_;
public:
    Son(int a, int b):father(a), b_(b) {}
    //virtual void SetA(int a) override {a_ = a;}
};

如father基类的SetA实现为"virtual void SetA(int a) final {a_ = a;}",则子类Son再多态继承实现SetA方法就会报错了。
3.3、建议:
构造与析构:全部的复制构造、赋值构造、移动构造、自定义构造函数,以及全部的赋值运算符、移动运算符,尽可能自行全部都实现
继承:子类的虚函数多态实现要加override显式的表明,不让子类多态实现的虚函数也要记得加入final;
宗旨:让c++11的编译器更多的帮助发现问题
4、lambda、bind、function:
函数式编程是c++11重要亮点之一
5、智能指针
reset自动析构再重新构造,get判断是否有效、支持放在容器内;
6、多线程与互斥同步(互斥锁,条件变量)
这也是c++11的一个重要亮点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值