Jialong's Blog
沉潜 自由 追寻幸福
Cpp11新特性总结

部分内容参考自知乎 - jameswhale - C++11新特性总结(相比C++98)

指针空值(0, NULL, nullptr)

nullptr与nullptr_t

=default

在C++中声明自定义的类,编译器会默认帮助程序员生成一些他们未显示定义的成员函数,包括构造函数、拷贝构造函数、拷贝赋值函数(operator =)、移动构造函数、移动拷贝函数、析构函数。一旦程序员实现了这些函数的自定义版本,则编译器不会再为该类自动生成默认版本。例如,声明了带参数的构造函数版本,则必须声明不带参数的版本以完成无参的变量初始化,而这会导致对应的类不再是POD的(非POD类型,意味着编译器失去了优化这样简单的数据类型的可能),通过=default 可以使其重新成为POD类型,见如下几个例子。

=delete

在以前,程序员若希望限制一些默认函数的生成,例如,单件类的实现需要阻止其生成拷贝构造函数和拷贝赋值函数,可以将拷贝构造函数和拷贝赋值函数声明为private成员,并且不提供函数实现,C++11 标准给出了非常简洁的方法,即在函数的定义或者声明加上”= delete“。

左值、右值

右值又称亡值、纯右值。

  • C++11新增了与右值引用相关的表达式。
  • 一般来说,左值引用不能接受一个右值,不过常量的左值引用能接受一个右值,比如函数指针的引用传递,const T&,可以减少临时对象的拷贝。

列表初始化

C++11新增了列表初始化方式,方便了代码编写。声明一个以initializer_list 模板类为参数的构造函数,自定义的类可以使用列表初始化方式。

int b[]{2, 4, 5};
vector<int> c{1, 3, 4};
map<int, float> d = {{1, 1.0f}, {5, 3.2f}};
int a = {3 + 4};
int a{3 + 4};

扩展了using的使用

using不只是用来声明命名空间了。

using uint = unsigned int;
template<typename T>
using MapString = map<T, char*>;
MapString<int> numberedString;

auto

auto作为新的类型指示符,用于自动推导,特别是命名空间、模板等导致类型很长的时候,非常方便。对于指针类型,声明为auto* 或者auto 是一样的,对于引用类型,必须使用auto &

decltype

以一个普通的表达式为参数返回该表达式的类型,在编译期进行。

基于范围的for循环

对于知道范围的数组和stl容器,C++11提供了for迭代访问能力,结合auto,可简化代码。需要满足两个条件:

  • 迭代的对象实现++和==操作;
  • 知道范围

多线程编程

C++11之前,在C/C++中程序中使用线程,主要使用POSIX线程(pthread),POSIX线程是POSIX标准中关于线程的部分,程序员可以通过pthread线程的api完成线程的创建、数据的共享、同步等功能。C++11引入了多线程的支持,使得C/C++语言在进行线程编程时,不必依赖第三方库和标准。

#include <atomic>		
#include <thread>		
#include <iostream>		
		
using namespace std;		
		
atomic_llong total{0};		
		
void func(int ){		
    for (long long i = 0; i < 100000000LL;++i){		
        total += i;		
    }		
}		
		
int main(){		
    thread t1(func, 0);		
    thread t2(func ,0);		
    t1.join();		
    t2.join();		
    cout << total << endl;		
    return 0;		
}

智能指针

C++11共有以下几种智能指针:

  • unique_ptr:拥有内存的所有权,没有拷贝构造函数,只有移动构造函数,不能多个unique_ptr对象共享一段内存,可以自定义delete函数,从而支持delete[]
  • shared_ptr:通过计数方式,多个shared_ptr可以共享一段内存,计数为0时,所管理的内存会被删除,可以自定义delete函数,从而支持delete[]
  • weak_ptr:观察shared_ptr管理的内存对象,只观察但不拥有。成员函数lock返回shared_ptr对象,若对应内存已经删除,则shared_ptr对象==nullptr,weak_ptr对象可以拷贝构造,拷贝构造出来的对象和原对象观察的是同一段内存。成员函数reset可以解除对内存的观察,注意,是解除观察,并不会删除对应内存对象。weak_ptr可以避免因为shared_ptr的循环引用引起的内存泄漏。

lambda表达式

#Pragma once 或 _Pragma(“once”)

用来保证头文件只会被include一次。_Pragma是一个操作符,可以用在宏定义中,比预处理指令灵活。

变长参数的宏定义

变长参数的宏定义指的是在宏定义中参数列表的最后一个参数为省略号,预定义宏__VA_ARGS__可以在宏定义的实现部分替换省略号代表队的字符串。

C/C++混用头文件

可以让如下头文件被#include到C文件中,也可以被#include到C++文件中,extern “C"可以抑制C++对函数名、变量名等符号进行重整,因此编译出的C目标文件和C++目标文件中的变量名和函数名都一样。

#ifdef __cplusplus
extern "C" {
#endif
    
    
#ifdef __cplusplus
"}"
#endif

常量表达式

  • 编译时常量:constexpr
  • 运行时常量:const

最后修改于 2022-02-25