C++11、C++14、C++17、C++20区别
C++11
c++11有如下的语言特性
- 移动语义
auto
类型推导- 右值引用
lambda
表达式initializer_list
初始化列表decltype
类型推导- 使用
using
的类型别名:using vec = std::vector<T>
nullptr
constexpr
常量表达式,使用constexpr
表明编译器在编译时期进行计算的表达式final
关键字,使得类不能被继承,函数不能被重写delete
关键字,使得类中的函数不能被使用- 转换构造函数,带有一个参数的构造函数
C++14
-
二进制字面常量:
0b110 = 6
、0b1111'1111 = 255
-
允许
auto
关键字可以放置在形参列表上,能够实现lambda
表达式的多态-
auto identity = [](auto x){ return x; }; int three = identity(3); std::string foo = identity("foo");
-
-
返回值类型推导,
auto
可以放置在函数的返回类型上,编译器将会自动推断出返回的类型-
auto f(int i) { return i; } template<typename T> auto& f(T& t) { return t; } auto g = [](auto& x)->auto& { return f(x); }; int y = 123; int& z = g(y); //对y的引用
-
-
decltype(auto)
:使用decltype(auto)
进行类型推断,会保持引用特性;-
const int x = 0; auto x1 = x; //int decltype(auto) x2 = x; //const int int y = 0; int& y1 = y; auto y2 = y1; //int decltype(auto) y3 = y1; // int& int&& z = 0; auto z1 = std::move(z); // int decltype(auto) z2 = std::move(z); // int&&
-
-
放松了
constexpr
函数的限制:在C++11中,constexpr
函数体中只可以包含有限的语法,仅仅包含一个return
语句。在C++14中,constexpr
函数可以包含多种语法,例如if
语句,循环等等。-
constexpr int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } factorial(5); // == 120
-
-
变量模板
-
template<class T> constexpr T pi = T(3.1415926535897932385); template<class T> constexpr T e = T(2.7182818284590452353);
-
C++17
-
类模板支持模板参数推导
-
template <typename T = float> struct MyContainer { T val; MyContainer() : val{} {} MyContainer(T val) : val{val} {} // ... }; MyContainer c1 {1}; // OK MyContainer<int> MyContainer c2; // OK MyContainer<float>
-
-
constexpr lambda
:编译时期的lambda
表达式-
auto identity = [](int n) constexpr { return n; }; static_assert(identity(123) == 123);
-
-
使用
auto
声明一个无类型的模板参数-
template <auto... seq> struct my_integer_sequence { // Implementation here ... }; // Explicitly pass type `int` as template argument. auto seq = std::integer_sequence<int, 0, 1, 2>(); // Type is deduced to be `int`. auto seq2 = my_integer_sequence<0, 1, 2>();
-
-
内联变量:
inline
可以应用在变量 -
嵌套的命名空间
-
namespace A { namespace B { namespace C { int i; } } } namespace A::B::C { int i; }
-
-
支持UTF-8字面值
-
支持折叠表达式:在模板参数包中支持折叠表达式,使用运算符作用在包中的每个元素。
-
template <typename... Args> bool logicalAnd(Args... args) { // Binary folding. return (true && ... && args); } bool b = true; bool& b2 = b; logicalAnd(b, b2, true); // == true template <typename... Args> auto sum(Args... args) { // Unary folding. return (... + args); } sum(1.0, 2.0f, 3); // == 6.0
-
-
lambda
表达式可以按值捕获this
指针-
struct MyObj { int value {123}; auto getValueCopy() { return [*this] { return value; }; } auto getValueRef() { return [this] { return value; }; } }; MyObj mo; auto valueCopy = mo.getValueCopy(); auto valueRef = mo.getValueRef(); mo.value = 321; valueCopy(); // 123 valueRef(); // 321
-
C++20
-
支持协程
-
支持
concepts
概念 -
指定的初始化器语法:任何没有列出名字的变量都被指定为默认初始化方式
-
struct A { int x; int y; int z = 123; }; A a {.x = 1, .z = 2}; // a.x == 1, a.y == 0, a.z == 2
-
-
模板可以应用在
lambda
表达式中-
auto f = []<typename T>(std::vector<T> v) { // ... };
-
-
lambda
表达式可以捕获参数包-
template <typename... Args> auto f(Args&&... args){ // BY VALUE: return [...args = std::forward<Args>(args)] { // ... }; } template <typename... Args> auto f(Args&&... args){ // BY REFERENCE: return [&...args = std::forward<Args>(args)] { // ... }; }
-
-
immdiate functions
:类似constexpr
函数,但是使用consteval
关键字声明,该函数必须产生一个常量值。-
consteval int sqr(int n) { return n * n; } constexpr int r = sqr(100); // OK int x = 100; int r2 = sqr(x); // ERROR: the value of 'x' is not usable in a constant expression // OK if `sqr` were a `constexpr` function
-
-
constexpr
虚函数:在C++20中,虚函数支持constexpr
-
struct X1 { virtual int f() const = 0; }; struct X2: public X1 { constexpr virtual int f() const { return 2; } }; struct X3: public X2 { virtual int f() const { return 3; } }; struct X4: public X3 { constexpr virtual int f() const { return 4; } }; constexpr X4 x4; x4.f(); // == 4
-
string、char*、char[]
char*
char* str = "this is GeeksForGeeks";
优点:
- 只需要一个指针即可指向整个字符串,高效利用内存;
- 不需要事先声明字符串的大小;
缺点:
-
不可以修改字符串,可以更改指针的指向,但是不能够更改指针所指的字符串;
-
char* str = "hello"; str[1] = 'o'; //错误的
-
-
使用这种方法在C语言中是可以的,但是在C++中不推荐,因为在C语言中,
string
字面值表示的是一个char
类型的数组,但是在C++中,字符串字面值表示的是一个常量的char
类型的数组,使用上面的方式,编译器会提示警告,所以在C++中应该使用const char* str = "字符串"
。
string
对于string
来说,其内部处理字符数组的存储,string
不用负责内存的分配和释放,而char*
需要考虑内存释放和越界问题;除此之外,string
内部封装了很多字符串处理的函数,例如查找,替换,搜索,插入等操作函数。
以下几种情况下使用char* 比使用std::string要好
- 与旧C代码兼容;
- 节省内存;
- 在与操作系统等底层系统进行通信时,适合使用
char*
;
char[]
char str[] = "This is GeeksForGeeks";
or
char str[size] = "This is GeeksForGeeks";
优点:
-
可以修改字符串;
-
char str[] = "Hello"; str[1] = 'o'; //正确
-
缺点:
- 在堆上分配空间,分配的空间是固定的。