C++11特性总汇

cnblogs 2024-07-26 14:39:00 阅读 59

预定义宏
    <li>

    211.预定义宏

  • 212.<code>__func__宏返回当前所在函数或结构体名字

    li>
  • 213.#pragma once/_Pragma(“once”)该头文件只编译一次

  • 214.__VA_ARGS__变长参数宏定义 #define PR(...) printf(__VA_ARGS__)

  • 215.宽窄字符串的连接

支持long long int类型

22.long long int n至少有64位

不同类型运算拓宽

23.(int)a + (long long int)b a会被提升为long long型后再进行运算

__cplusplus

24.用于C/C++混合编写, __cplusplus = 201103L可用作检测编译器所支持的C++版本

#ifdef __cplusplus

extern "C" {

#endif

//some code

#ifdef __cplusplus

}

#endif

assert断言
    <li>(1) 包含在<code><cassert>的断言assert(n > 0);运行时若n不大于0则报错

    (2) 静态断言static_assert(sizeof(a) == sizeof(b), "must have same width");编译时报错,不可使用变量进行静态断言

    li>
noexcept关键词
    <li>

<code>void func() noexcept(true);

若有异常,选择不抛出,而是直接终止运行并报错,括号内常量表达式true=不抛出, false=抛出

花括号初始化非静态成员
    <li>

<code> private:

string name{"ABC"};

允许对非静态成员使用sizeof
    <li>

<code> private:

int n; //sizeof(class::n)可编译通过

友元模板

29.可在模板使用友元friend T;

final/override关键词
    <li>

<code> private:

void func() final; //派生不可重载

void oldFunc() override; //重载必须同名,同参数,同常量性,且被重载的是虚函数

默认模版类型
    <li>

<code> template<typename T1, typename T2 = int> class C1; //通过

template<typename T1 = int, typename T2> class C2; //报错,类模版默认类型需要从右往左

template<typename T1 = int, typename T2> void func(T1 a, T2 b); //通过,函数模版没有这规定

外部模版
    <li>

<code>extern template void func<int>(int);

继承构造函数
    <li>

<code>struct B: A{

using A::A;

};

委派构造函数
    <li>

<code>class A{

public:

A() : A(1234){} //先调用A(int)

A(int n1) : A(n1, 'C'){} //先调用A(int, char)

A(char c1) : A(2, c1){} //先调用A(int, char)

private:

A(int n2, char c2) : my_int(n2), my_char(c2){}

int my_int;

char my_char;

}


应用于模版:

class A{

public:

A(vector<int> &v) : A(v.begin(), v.end());

A(deque<short> &d) : A(d.begin(), d.end());

private:

template<class T> A(A n1, T n2): my_list(n1, n2) {}

list(int) my_list;

}


捕捉异常:

class A{

public:

A()

try : A(1234) {init();}

catch(...) {error();}

A(int n) {throw 0;}

//构造时执行error(), 而不执行init()

}

右值引用
    <li>
  • 331.指针成员拷贝构造

<code>class A{

public:

A() : my_ptr(new int(1234)) {}

A(A &copy) : my_ptr(new int(*copy.my_ptr)) {}//新申请一块内存,避免重复析构同一块内存

~A() {delete my_ptr;}

int *my_ptr;

}


  • 332.移动语义

class A{

public:

A() : my_ptr(new int(1234)) {}

A(const A& copy) : my_ptr(*copy.my_ptr) {}

A(A&& move) : my_ptr(move.my_ptr) {move.my_ptr = nullptr;}

~A() {delete my_ptr;}

int* my_ptr;

}

A GetTmp() {

A tmp;

return tmp;

}

int main(){

A one = GetTmp();

}

1.执行GetTmp(),创建A1并初始化后返回,

2.创建并初始化A2,即A2(A1), 执行的是move而不是copy,它将A1的指针赋值给A2,并将A1的指针清掉,

3.析构A1,由于指针清掉了,所以初始化时的内存没有被释放

4.创建并初始化one,即one(A2),重复第2步,第3步

5.析构one,此时内存才真正被释放,它是A1初始化时申请的


  • 333.有名字的是左值, 没名字的是右值, 左值*p=1234, 右值p=1234

  • 334.在<utility>中提供了std::move函数,它将左值强制转化为右值引用

  • 335.swap(T a, T b)函数使用移动语义进行交换,

    移动构造函数不应该写抛出异常,

    编译选项-fno-elide-constructors关闭优化以使用移动/拷贝语义,否则变量直接替换成右值进行编译


  • 336.完美转发

引用折叠规则:

typedef int T;

typedef T& TR; //or typedef T&& TR

TR a; //or TR& a , TR&& a

TR定义为T&时,a的类型都是A&

TR定义为T&&时,TR/TR&&的类型为A&&,TR&的类型为A&


template <typename T, typename U>

void PF(T&& t, U& func){

func(std::forward<T>(t));

}

forward()move()功能相同,完美转发能够把引用类型准确传给调用函数

explicit显式转换操作符
    <li>

<code>class A{}

class B{

public:

explicit operator A() const {return A();}

}

void func(A a){}

void main(){

B b;

A a1(b); //通过,直接初始化

A a2 = b; //错误

A a3 = static_cast<A>(b); //通过,显式转换

func(b); //错误

}

351.列表初始化, 头文件<initializer_list>,声明一个以initialize_list<T>模版类为参数的构造函数,就能够使自定义类使用列表初始化

void func(initializer_list<int> numbers){}

int main(){

func({1, 2, 3});

func({});

}

352.使用花括号初始化可以防止类型收窄

const int x = 1234;

char a = x; //通过

char b = {x}; //错误

char* c = new char(1234); //通过

char* d = new char{1234}; //错误

36.POD类型

37.联合体

38.用户自定义字面量

39.内联名字空间

inline namespace space1{

class A{};

}

namespace space2{

A a;//A in space1

class A{};

A b;//A in space2;

}

310.模版的别名

template<typename T> using NewName = std::map<T, char*>;

NewName<int> a; //等同于std::map<int, char*> a;

311.SFINAE规则:特殊场景使用特殊模板版本,另外则是通用模板版本

struct A{ typedef int my_int;

};

template <typename T>

void func(typename T::my_int) {} //#1

template <typename T>

void func(T) {} //#2

int main(){

func<A>(1234); //调用#1,因为存在A::my_int

func<int>(1234); //调用#2,因为不存在int::my_int

}

>>右尖括号

41.两个右尖括号>在模板中不再被判定为右移, 需要右移需要加圆括号()

auto类型推导
    <li>

<code>int a = 1;

auto b = a; //b的类型为int

编译时推导

1): auto不能作函数形参类型

2): auto不能对结构体中的肥静态成员进行推导

3): auto不能声明数组

4): auto不能在实例化模板时作为模板参数


decltype类型推导

43.

int a = 1;

decltype(a) b; //b的类型为Int

uding size_t = decltype(sizeof(0)); //与using/typydef合用

编译时推导

1): decltype不能推导重载的函数

2): decltype将亡值推导为右值引用

3): decltype将左值推导为引用, 如 三元运算符, 带圆括号的左值, ++i, arr[0], *ptr

4): 以上都不是,则推导为本类型


追踪返回类型
    <li>

<code>template<typename T1, typename T@>

auto Func(const T1& a, const T@& b) -> decltype(a + b){

return a + b;

}

编译时推导

基于范围的for循环
    <li>

<code>vector<int> MyVector= {1, 2, 3, 4};

for(auto p : MyVector)

{

cout << p << endl; //p是解引用后的对象, 无需再*p解引用

}

条件: 迭代对象要实现++==等操作符,普通已知长度的数组(未知长度的不行), 类要有begin函数和end函数

强类型枚举
    <li>

<code>enum class MyEnum: char{ e1, e2, e3}; //定义一个以char为底层实现的强类型枚举

MyEnum a = e1; //错误

MyEnum b = MyEnum::e1; //通过

MyEnum c = 2; //错误

Myenum d = MyEnum::e2;

if(d > 1){} //错误

if((char)d > 1){} //通过

智能指针
    <li>

<code>unique_ptr<int> up1(new int(11)); //无法被复制

unique_ptr<int> up2 = up1; //编译错误, 指针唯一

unique_ptr<int> up3 = move(up1); //up1的控制权转移给up3

up3.reset(); //显式释放

up1.reset(); //不会出错

unique_ptr只允许唯一指针指向内存

shared_ptr则允许共享同一块内存,它在实现上采用了引用计数,只有在计数归零时才真正释放内存

weak_ptr不拥有控制权,其成员函数lock()返回其指向内存的一个shared_ptr对象,若其内存无效则返回nullptr

constexpr常量表达式
    <li>

函数:

<code>constexpr int GetConst(){return 1;}

1): 函数体只能有单一的return返回语句

2): 函数必须有返回值(不能为void)

3): 使用前必须已定义,即函数定义写在调用函数前面(放至后面则出错)

4): return返回语句表达式中必须是一个常量表达式,且不能是运行时函数


:

constexpr int a = 1;

它是编译时期的值,编译器可以选择不为它生成数据


自定义类: 必须对构造函数加上constexpr关键词

struct MyType{

constrxpr MyType(int x): my_int(x){}

int my_int;

}

constexpr MyType mt = {2};

1): 构造函数的函数体必须为空

2): 初始化列表只能由常量表达式来赋值

变长模板
    <li>

<code>template <typename T1, typename T2>

class A{};

template <typename... SomeType>

class B: private A<SomeType...>{};

B<int, char> xy;

typename之后带...来说明这是一个参数包,该包名字为SomeType

构造类型B时,会调用B的私有基类构造函数,并进行参数包展开

即实际上执行的是A<int, char> xy;


template <typename... B>

class MyClass;

template <typename A, typename... B>

class MyClass<A, B...>: private MyClass<B...>{

A my_a;

};

template<>

class MyClass<>{};

递归定义,在参数个数为0时结束,从右往左

参数包可以展开的位置:

1): 表达式

2): 初始化列表

3): 基类描述列表

4): 类成员初始化列表

5): 模板参数列表

6): 通用属性列表

7): lambda函数的捕捉列表


template <typename... A>

class MyClass1: private OldClass<A...>{};

Myclass1 C1<X, Y>;

//解包为 class MyClass1: private OldClass<X, Y>{};

template <typename... A>

class MyClass2: private OldClass<A>...{};

Myclass2 C2<X, Y>;

//解包为 class MyClass2: private OldClass<X>, private OldClass<Y>{};

template <typename... A>

int GetSize(A... args){

int size = sizeof...(A); //使用sizeof...()获取参数包的大小(个数)

return size;

}

原子操作
    <li>头文件<code><atomic>, <thread>li>

atomic_int at1 {0};

atomic<int> at2 {0};

int Set(){

at1 = 1;

at2 = 2;

}

int Show(){

cout << at1 << ", " << at2 << endl; //可能输出(1,0)/(0,2)/(1,2)

}

int main(){

thread t1(Set, 0);

thread t2(Show, 0);

t1.join();

t2.join();

cout << at1 << ", " << at2 << endl; //必输出 1, 2

}

由于编译器的优化,执行时可能会打乱实际的代码顺序

所以需要显式使用原子类的成员函数写入store()和读取load()

这些函数有2个参数,第一个是值,第二个是操作类型

操作枚举值:

memory_order_relaxed不对执行顺序作保证

memory_order_acquire本线程中,所有后续的读操作必须在本条原子操作完成后执行

memory_order_release本线程中,所有之前的写操作完成之后才能执行本条原子操作

memory_order_acq_rel同时包含memory_order_acquirememory_order_release

memory_order_consume本线程中,所有后续的有关本原子类型的操作,必须在本条原子操作完成后执行

memory_order_seq_cst全部存取按照顺序执行

store()可用:

memory_order_relaxed,

memory_order_release,

memory_order_seq_cst

load()可用:

memory_order_relaxed,

memory_order_consume,

memory_order_acquire,

memory_order_seq_cst

RMW(Read Modify Write)同时读写操作可用: 全部

thread_local线程局部变量
    <li>

<code>int thread_local tl;

quick_exit() / at_quick_exit()快速退出
    <li>

<code>struct A{}{

~A(){};

}

void Func(){}

int main(){

A a;

at_quick_exit(Func); //注册一个函数,在quick_exit时FILO执行

quick_exit(0); //A的析构函数不执行

}

nullptr指针空值
    <li>
<code> = default 和 = delete 默认函数
    <li>

<code>class A{

public:

A() = default; //使用默认构造函数, 保持POD类型

A(const A&) = delete; //删除该函数, 且禁止重载该函数

};

lambda函数(局部函数)
    <li>

<code>int a = 1, b = 2;

auto Func1 = [=]() -> int{

return a + b;

};

int c = Func1(); //c = 3

auto Func2 = [](int i1, int i2) -> int{

return i1 + i2;

}

int d = Func2(a, b); // d = 3

[var]值传递方式捕捉变量var

[=]值传递方式捕捉所有父作用域的变量,包括this

[this]值传递方式捕捉当前this

[&var]引用传递方式捕捉变量var

[&]引用传递方式捕捉所有父作用域的变量,包括this

[&this]引用传递方式捕捉当前this

数据对齐
    <li>

<code>alignas(double) int a = 1; //a按照double类型宽度对齐

alignas(alignof(double)) int b = 1; //效果相同, alignof用于获取类型的宽度

通用属性
    <li>
Unicode
    <li>
原生字符串
    <li>

参考资料: <<深入理解C++11: C++11新特性解析与应用>>



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。