C++新特性学习

一、C++11新特性

1、auto自动类型推导

1、当类型不为引用时,auto的推导结果将不保留表达式的const属性;当类型为引用时,auto的推导结果将保留表达式的const属性。

2、C++11限制:auto不能在函数的参数中使用,不能作用于类的非静态成员变量,不能作用于模板参数,不能用于推导数组类型。还不能让普通函数具备返回值推导(C++14才行)。

2、decltype右值引用

1、作为操作符,用于查询表达式的数据类型。而auto只能用于返回变量的数据类型。

2、右值引用,也是别名,但其只能对右值引用

cpp 复制代码
//decltype关键字-推导表达式的类型,常用于模板编程
int x = 5;
decltype(x) y = x; // y 是 int
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
	return t + u;
}

3、移动语义 列表初始化 for each等

1、可以将资源从一个对象转移到另一个对象,这样可以减少不必要的临时对象的创建、拷贝及销毁。移动语义与拷贝语义是相对的,可以类比剪切与拷贝。在现有C++机制中,自定义的类要实现转移语义,需要定义移动构造函数,还可以定义转移赋值操作符。

2、左值:有地址、有名字的表达式(如变量)。右值:临时对象、字面量(如函数返回的局部对象),右值引用用&&表示,可以延长临时对象的生命周期。

cpp 复制代码
int x = 10; // x 是左值
int&& r = 20; //20 是右值,r 是右值引用
string getName() {
	string s = "hello";
	return s; //返回局部对象(右值)
}
string&& name = getName(); // 右值引用延长生命周期
//移动构造函数
class StringWrapper {
public:
	//移动构造函数:转移资源,而非复制
	StringWrapper(StringWrapper&& other) noexcept
		: data_(other.data_), size_(other.size_) {
		other.data_ = nullptr; //源对象不再拥有资源
	}
private:
	char* data_;
	size_t size_;
};

//move:将左值转换为右值引用
vector<int> v1 = { 1, 2, 3 };
vector<int> v2 = move(v1);// v1 的资源被转移,v1变为空
//完美转发forward-在模板中保持参数的左值/右值属性
template<typename T>
void wrapper(T&& arg) {
	//完美转发arg给worker,保持其值类别
	worker(forward<T>(arg));
}

4、lambda

实际上是一个匿名类函数。

1、capture-list:捕抓列表,该列表总是出现在lambda函数的开始位置,编译器根据\[\]来判断接下来的代表是否为lambda函数,捕抓列表能够捕抓上下文中的变量提供lambda函数使用。

描述了上下文哪些数据可以被lambda使用,以及使用的方式传值还是传引用。

a,\&b其中a以复制捕获而b以引用捕获。this以引用捕获当前对象(*this)。\&以引用捕获所有用于lambda体内的自动变量,并以引用捕获当前的对象,若存在。=以复制捕获所有用于lambda体内的自动变量,并以捕获当前对象,若存在。\[\]不捕获,大部分情况下不捕获就可以了。

2、(parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。

3、mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常变量性,使用该修饰符时,参数列表不可省略(即使参数为空)。mutable放在参数列表和返回值之间。

4、->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

5、{statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。(不能省略)。

cpp 复制代码
int main() {
	//基本语法:[捕获列表](参数列表) -> 返回类型 { 函数体 }
	vector<int> v = { 1, 2, 3 };
	sort(v.begin(), v.end(),
		[](int a, int b) {return a > b; }
	);
	//捕获外部变量
	int base = 10;
	for_each(v.begin(), v.end(), 
		[base](int n) {cout << n + base << " "; }
	);
	//按值捕获 =,按引用捕获 &
	auto lambda = [=](int x, int y) {return x + y; };

	return 0;
}

5、智能指针

都是以模板的形式来实现的。使用时,#include<memory> using namespace std;

1、shared_ptr:和其他两个不同之处在于,多个shared_ptr智能指针可以共同使用同一块堆内存。并且,由于该类型智能指针在实现上采用的是引用计数机制,即便有一个shared_ptr指针放弃了堆内存的shared_ptr指针(只有引用计数为0时,堆内存才会被自动释放)。

2、unique_ptr:指针自然也具备"在合适时机自动释放堆内存空间"的能力。和shared_ptr指针最大不同之处在于,unique_ptr指针指向的堆内存无法同其它unique_ptr共享,也就是说,每个unique_ptr指针都独自拥有对其所指堆内存空间的使用权。

3、weak_ptr:shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对象,并维护了一个共享的引用计数器。对于引用计数法实现的计数,总是避免不了循环引用的问题,shared_ptr也不例外。

cpp 复制代码
//unique_ptr:独占所有权
unique_ptr<int> p1(new int(5));
//unique_ptr<int> p2 = p1 //错误:不能拷贝
unique_ptr<int> p3 = move(p1);//可以移动

//shared_ptr:共享所有权(引用计数)
shared_ptr<int> sp1 = make_shared<int>(10);
shared_ptr<int> sp2 = sp1;// 引用计数+1

//weak_ptr:弱引用,解决shared_ptr循环引用问题
class Node {
public:
	shared_ptr<Node> next;
	weak_ptr<Node> prev; //弱引用,不增加计数
};

6、constexpr:编译期计算

在编译期执行函数,提高运行效率。

cpp 复制代码
constexpr int factorial(int n) {
	return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
	constexpr int f5 = factorial(5);//编译期计算为120
	int arr[f5];					//合法:数组大小需要常量表达式
}

7、并发支持<thread>

cpp 复制代码
void worker() {
	cout << "Thread ID:" << this_thread::get_id() << endl;
}
int main() {
	thread t(worker);
	t.join();//等待线程结束
	//原子操作
	atomic<int> counter(0);
	counter.fetch_add(1);
}

8、其他重要特性

nullptr:类型安全的空指针,替代NULL

override/final:明确虚函数重写和禁止重写

=default / =delete:显式控制默认函数

static_assert:编译期断言

哈希表容器:unordered_map/unordered_set

正则表达式库<regex>

随机表达式库<random>

时间库<chrono>

二、C++14新特性

1、泛型Lambda

允许lambda参数使用auto,让lambda称为模板

cpp 复制代码
//C++11:必须指定类型
auto add = [](int a, int b) {return a + b; };

//C++14:泛型lambda
auto add2 = [](auto a, auto b) {return a + b; };

2、Lambda捕获初始化

支持用任意表达式初始化捕获变量,实现移动捕获

cpp 复制代码
auto ptr = make_unique<int>(10);

//C++14:移动捕获
auto lambda = [ptr = move(ptr)]() {
	return *ptr;
};

3、函数返回类型推导

cpp 复制代码
auto add(int a, int b) {
	return a + b;
}
auto getValue() {
	if (true)return 1;//所有return必须推导为相同类型
	else return 2;
}

4、decltype(auto)

结合decltype的推导规则和auto的语法

cpp 复制代码
int x = 5;
int& y = x;
decltype(auto) z = y; // z 是 int& (而不是 int)

5、constexpr增强

constexpr函数可以包含循环、条件语句等。

cpp 复制代码
//C++14允许循环,条件语句
constexpr int factorial(int  n) {
	int result = 1;
	for (int i = 2; i <= n; ++i) {
		result *= i;
	}
	return result;
}

6、标准库新增

make_unique:创建unique_ptr的工厂函数。shared_timed_mutex:共享互斥体

三、C++17新特性

1、结构化绑定

将结构体、数组、pair/tuple的成员解包到独立变量

cpp 复制代码
struct Point { int x, y; };
Point p{ 10, 20 };
auto [x, y] = p;
map<int, string> m = { {1, "one"}, {2, "two"} };
int main() {
	for (const auto& [key, val] : m) {
		cout << key << ":" << val << endl;
	}
	tuple<int, double, string> t = { 42, 3.14, "hello" };
	auto [a, b, c] = t;
	return 0;
}

2、if和switch的初始化语句

在条件表达式中定义变量,限制作用域。

cpp 复制代码
map<int, string> mp = { {1, "one"}, {2, "two"} };
int main() {
	//C++17 before
	auto it = mp.find(1);
	if (auto it = mp.find(1); it != mp.end()) {
		//使用it
	}
	else {
		//it仍然可以使用
	}
	//it超出了作用域
	return 0;
}

3、内联变量

解决头文件中定义全局变量的多重定义问题。

cpp 复制代码
//头文件中,C++17可以直接定义
inline int global_counter = 0;
class MyClass {
	static inline int instance_count = 0; //类内定义静态成员
};

4、optional

表示可能存在或不存在的值,替代特殊值(如-1)表示无效。

cpp 复制代码
map<int, string> mp = { {1, "one"}, {2, "two"} };
optional<string> findValue(const string & key) {
		if (auto it = mp.find(key); it != mp.end())
			return it->second; //返回值
		return nullopt; //表示没找到
	}
int main() {
	
	auto result = findValue("key");
	if (result.has_value()) {
		cout << "Found:" << result.value() << endl;
	}
}

5、variant

类型安全的联合体union,可存储多种类型之一。

cpp 复制代码
std::variant<int, double, std::string> v;

v = 42;
v = 3.14;
v = "hello";

// 访问方式:std::visit
std::visit([](auto&& arg) {
    std::cout << arg << '\n';
}, v);

6、string_view

非拥有的字符串视图,避免拷贝。

cpp 复制代码
void process(string_view sv) {
	//避免了 string 的深拷贝
	cout << sv.substr(0, 5);
}
string s = "very long string";
int main() {
	process(s); //不拷贝
	process("literal"); //直接使用字面量

	return 0;
}

7、filesystem

跨平台的文件系统操作库

cpp 复制代码
fs::path p = "/home/user/file.txt";
int main() {
	cout << p.filename() << endl;
	cout << p.extension() << endl;
	for (const auto& entry : fs::directory_iterator(".")) {
		cout << entry.path() << endl;
	}

	return 0;
}

8、并行STL算法

支持多线程并行执行算法。

cpp 复制代码
vector<int> v(100000);
int main() {
	sort(execution::par, v.begin(), v.end());
	return 0;
}

9、折叠表达式

简化可变参数模板的展开。

cpp 复制代码
template<typename... Args>
auto sum(Args... args) {
	return (args + ... + 0);//折叠表达式
}
int main() {
	sum(1, 2, 3, 4);//1 + 2 + 3 + 4 = 10
}

10、if constexpr

编译期条件判断,只编译符合条件的分支

cpp 复制代码
template<typename T>
auto getValue(T t) {
	if constexpr (is_pointer_v<T>) {
		return *t; //仅当T是指针时编译
	}
	else {
		return t; // 仅当T不是指针时编译
	}
}

四、C++20新特性

1、Concept概念

对参数模板参数进行约束,提供更清晰的错误信息citation:9

cpp 复制代码
#include<concepts>
//定义概念:要求类型T支持加法
template<typename T>
concept Addable = requires(T a, T b) {
	{ a + b } -> same_as<T>;
};
//使用概念约束模板参数
template<Addable T>
T add(T a, T b) {
	return a + b;
}
int main() {
	add(1, 2);
	add(1.5, 2.5);//OK
	//add("hello", "hello"); //错误:不满足Addable概念
}

2、范围(Ranges)

更直观、函数式风格的容器操作citation:9

cpp 复制代码
#include<ranges>
namespace views = views;
vector<int> v = { 1, 2, 3, 4, 5, 6 };
//传统写法
vector<int> even;
copy_if(v.begin(), v.end(), back_inserter(even),
	[](int x) {return x % 2 == 0; });

//Ranges 写法:链式调用
auto result = v
| views::filter([](int x) {return x % 2 == 0; }) //过滤偶数
| views::transform([](int x) {return x * x; })   //求平方
| views::take(2);  //取前两个

3、携程

支持异步编程,可暂停和恢复的函数。

4、三向比较运算符(<=>)

cpp 复制代码
struct Point {
	int x, y;
	//自动生成所有比较运算符(==,!=,<,<=,>,>=)
	auto operator<=>(const Point&)const = default;
};
int main() {
	Point p1{ 1, 2 }, p2{ 1, 3 };
	cout << (p1 < p2); //true,因为y比较
	return 0;
}

5、模块(Modules)

替代头文件的现代化编译单元,加快编译速度citation:9

cpp 复制代码
//math.ixx
export module math;
export int add(int a, int b) {
	return a + b;
}
//main.cpp
import math;//不再需要 #include
int main() {
	return add(3, 4);
}

6、格式化库(format)

类型安全的,类似python的字符串格式化。

cpp 复制代码
#include<format>
string s = format("Hello, {}! The answer is {}", "world", 42);
//s = "Hello, world! The answer is 42"
//位置参数
string s2 = format("{1} {0}", "world", "Hello");//"Hello world"

7、span

非拥有的连续序列视图,比指针+长度更安全。

cpp 复制代码
#include<span>
void process(span<int> buffer) {
	for (int& x : buffer) {
		x *= 2;
	}
}
int main() {
	vector<int> vec = { 1, 2, 3, 4 };
	process(vec);//传递vector
	int arr[] = { 5, 6, 7, 8 };
	process(arr);//传递数组
	return 0;
}

五、C++23

在C++20上做了小幅度改进和改善。

主要特性

expected:带错误信息的返回值类型

mdspan:多维数组视图

print/println:更简洁的输出函数

Ranges库的增强:ranges::to等性新功能

this推导:允许lambda使用显式this参数

stacktrace:栈追踪支持

标准库模块import std:一站式导入标准库

相关推荐
Hello:CodeWorld27 分钟前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法
十月的皮皮2 小时前
C语言学习笔记20260606- 求月份天数三种写法
c语言·笔记·学习
马士兵教育3 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习
搬砖魁首3 小时前
基础能力系列 - 多线程2 - 条件变量
c++·rust·条件变量·原子类型·线程同步互斥
chase_my_dream3 小时前
C++ + SLAM 高频面试问题整理
开发语言·c++·面试
牛油果子哥q3 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++
lizhihai_994 小时前
股市学习心得-AI 产业链核心标的梳理清单
大数据·服务器·人工智能·科技·学习
吃好睡好便好4 小时前
说说科学爬山
学习·生活
lunzi_08265 小时前
【学习笔记】《Python编程 从入门到实践》第8章:函数定义、参数传递与模块导入
笔记·python·学习