前言

C++标准定义了 C++ 语言的语法、语义、标准库等核心内容,是编译器、开发者遵循的统一准则;核心目标是解决历史痛点、适配现代编程需求、提升性能与易用性,同时保持向后兼容

1 C++11

1.1 核心语言特性模块

(1) 自动类型推导

//int
auto iNum = 1; 
//double
auto dNum = 3.1415; 

编译器根据变量的初始化表达式在编译期推导类型,不影响运行时性能

(2) 范围for循环

for(const auto &tmp : vInts){...}

(3) 空指针常量

int *ptr = nullptr;

nullptr是全新的关键字,类型为std::nullptr_t,可隐式转换为任意指针类型,但不可转换为整数

(4) 类型别名using

// C++98 typedef
typedef std::vector<int> VInts;
// 函数指针别名(可读性差)
typedef void (*funcPtr)(int); 

// C++11 using
using vInts = std::vector<int>;
// 函数指针别名更直观
using funcPtr = void (*)(int); 
template <typename T>
using Vec = std::vector<T>;
// 支持模板类型的别名
Vec<int> vAges = {12,14,15}; 

using是 C++11 引入的类型别名语法,支持 “模板别名”(别名模板),语法更直观

(5) Lambda表达式

auto add = [](int a, int b) { return a + b; };
auto sum = add(3, 4);

(6) 移动语义和右值引用

std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = std::move(vec1);  // 移动,vec1现在为空,vec2拥有vec1原来的元素

本质是资源窃取资源,“鸠占鹊巢,赶尽杀绝”;move是将左值引用转为右值引用,提升了代码的性能

(7) override 和 final 关键字

class Base {
public:
    virtual void func() const;
    // 禁止派生类重写
    virtual void doSomething() final;  
};

class Derived : public Base {
public:
	// 明确表示重写基类虚函数
    void func() const override;  
};

(8) 静态断言static_assert

// C++98 - 只能在运行时断言
#include <cassert>
assert(sizeof(int) == 4);

// C++11 - 编译时断言
static_assert
	(sizeof(int) == 4, "int必须是4字节");
static_assert
	(sizeof(void*) == 8, "要求64位系统");

(9) 原始字符串字面量

// C++98 - 需要转义
std::string path = 	
	"C:\\MyApp\\a.txt";

// C++11 - 原始字符串,无需额外的转义
std::string path = 	
	R"(C:\MyApp\a.txt)";

(10) 用户定义字面量

// 定义字面量运算符
long double operator"" _km(long double val) 
{
	// 公里转米
    return val * 1000.0;  
}
// 使用(5000米)
auto distance1 = 5.0_km;  

1.2 标准库模块

(1) 智能指针

#include <memory>

// std::unique_ptr - 独占所有权
std::unique_ptr<Resource> p1(new Resource());
// C++14,但理念来自C++11
auto p2 = 
	std::make_unique<Resource>();  

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

// std::weak_ptr - 弱引用,打破循环引用
std::weak_ptr<Resource> wp = sp1;

(2) 并发支持

#include <thread>
#include <mutex>
#include <future>
#include <atomic>

// 线程
std::thread t([](){
    std::cout <<
    	"Hello from thread!" 
    	<< std::endl;
});
//C++11标准库启动线程之后,要么join阻塞要么分离
t.detach(); 

// 互斥锁
std::mutex mtx;
// RAII锁管理
std::lock_guard<std::mutex> lock(mtx); 

// 异步任务 std::async 可以自动创建线程
// 并在任务完成后自动回收线程资源
auto future = std::async(std::launch::async, [](){
    return computeSomething();
});
// 异常会在调用 future::get() 时重新抛出
// 从而允许在主线程中处理异常
//主线程可以做其他事情,在需要结果的时候调用get函数
int result = future.get(); 

// 原子操作
std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed);
A 异步任务的四大组件
  • 任务启动器:std::async

    // 启动异步任务的各种方式
    auto future1 = 
    	std::async(std::launch::async,
            []() -> std::string 
            { return "Hello"; }
    	);
    
  • 结果占位符:std::future

    // 启动异步任务的各种方式
    auto future1 = 
    std::async(std::launch::async, 
        []() -> std::string 
        { return "Hello"; }
    );
    auto res = feature1.get();
    
  • 结果设置器:std::promise

  • 调用包装器:std::package_task

    // 将任意可调用对象包装成异步任务
    std::packaged_task<int(int, int)> 
    	task([](int a, int b) 
    	{
        	return a * b;
        });
    std::future<int> result = 
    	task.get_future();
    

(3) 正则表达式:std::regex

#include <regex>
// 美国SSN格式
std::regex pattern(R"(\d{3}-\d{2}-\d{4})");  
std::string text = "My SSN is 123-45-6789";

if (std::regex_search(text, pattern)) {
    std::cout << "Found SSN!" << std::endl;
}

// 替换
std::string masked = 
	std::regex_replace(text, pattern, "XXX-XX-XXXX");

(4) 元组:std::tuple

#include <tuple>
// 创建元组
std::tuple<int, double, std::string> 
	tup(1, 2.5, "hello");

// 访问元素
int a = std::get<0>(tup);
double b = std::get<1>(tup);

// 结构化绑定(C++17)的前身
int x; double y; std::string z;
// 解包元组
std::tie(x, y, z) = tup; 

(5) 哈希容器:std::unordered_map, std::unordered_set

#include <unordered_map>
#include <unordered_set>
// 哈希映射,平均O(1)查找
std::unordered_map<std::string, int> 
	phonebook = {
        {"Alice", 123456},
        {"Bob", 987654}
	};
// 哈希集合
std::unordered_set<int> unique_numbers = 
	{1, 2, 3, 4, 5};

(6) 容器数组:std::array

#include <array>
// 固定大小数组,STL风格接口
std::array<int, 5> arr = 
	{1, 2, 3, 4, 5};

// 相比原生数组的优势
// 有size()方法
size_t size = arr.size();  
// 边界检查(抛出异常)
arr.at(2) = 10;  

(7) 初始化列表

#include <initializer_list>

class MyContainer {
    std::vector<int> data;
public:
    MyContainer(std::initializer_list<int> init) : 
    	data(init) {}
};
// 使用初始化列表
MyContainer c = {1, 2, 3, 4, 5}; 

(8) 包装器

#include <functional>

// std::function - 通用函数包装器
std::function<int(int, int)> add = 
	[](int a, int b) { return a + b; };
std::function<void()> printHello = 
	[]() { std::cout << "Hello"; };

// std::bind - 参数绑定
using namespace std::placeholders;
// 绑定第一个参数为5
auto add5 = std::bind(add, 5, _1);  
// 相当于 add(5, 10)
int result = add5(10);  

1.3 新增关键字

// C++11新增的关键字,不能用作标识符
alignas         alignof          
char16_t        char32_t        
constexpr       decltype        
noexcept        nullptr         
static_assert   thread_local     

2 C++14

C++14是C++11之后的一个小版本更新,主要目标是完善C++11的特性,提供一些小的改进和bug修复,而不是引入大的新特性

2.1 核心语言特性模块

(1) Lambda提升

泛型Lambda:

// C++11:Lambda参数必须指定具体类型
auto lambda = 
	[](int x, int y) {return x+y;};

// C++14:Lambda可以是泛型的
auto generic_lambda = 
	[](auto x, auto y) {return x+y;};

初始化捕获:

// C++11:只能按值或按引用捕获现有变量
int x = 10;
auto lambda = [x]() { return x; };

// C++14:可以用表达式初始化捕获的变量
auto lambda1 = 
	[value = 42]()  // 直接初始化
	{ 
		return value;
    }; 

移动捕获:

// 最重要的应用:移动捕获(Move Capture)
// C++11中无法直接移动捕获,需要复杂技巧
// C++14可以轻松实现
std::unique_ptr<int> ptr(new int(42));
auto lambda3 = [ptr = std::move(ptr)]() 
{
    return *ptr;
};

// 在异步编程中特别有用
auto async_task = 
	[data = std::move(large_data)]() 
	{
        // 安全地使用data,所有权已转移
        process(data);
	};
std::thread t(std::move(async_task));

(2) 函数返回类型推导扩展

放松了对auto返回类型的限制

// C++11:返回auto需要尾置返回类型或只能用于Lambda
auto func() -> int { return 42; }

// C++14:普通函数可以直接用auto推导返回类型
// 多个return语句必须返回相同类型
auto get_answer(int iType) 
{
	if(1==iType)
		return -1
	else
		// 推导为int
   	 	return 42;  
}

auto add(auto a, auto b) 
{
	// 推导为a+b的类型
    return a + b;  
}

(3) 变量模板

// C++11:常量模板需要用类模板或函数模板
template<typename T>
struct pi_constant {
    static constexpr T value = 
    	T(3.14159265358979323846);
};

// C++14:可以直接定义变量模板
template<typename T>
constexpr T pi = 
	T(3.14159265358979323846);

(4) 二进制字面常量

// 使用0b或0B前缀
int binary = 0b101010;  // 42
int with_separator = 0b1010'1010; // 170

// 实际应用:位掩码、硬件编程
constexpr uint8_t READ = 0b00000001;
constexpr uint8_t WRITE = 0b00000010;
constexpr uint8_t EXECUTE = 0b00000100;

uint8_t permissions = READ | WRITE;

(5) 聚合类成员初始化

// C++11:聚合类(没有用户提供的构造函数)不能有成员初始化器
struct Point11 {
    int x;
    int y;
    // 不能在这里写 int x = 0; // C++11错误
};

// C++14:允许聚合类有成员初始化器
struct Point14 {
    int x = 0;  // 默认值
    int y = 0;
};

2.2 标准库模块

(1) 智能指针:std::make_unique

// C++14新增:make_unique
auto p1 = std::make_unique<int>(42);
auto p2 = std::make_unique<std::string>("Hello");

(2) 并发模块:读写锁支持<shared_mutex>

#include <shared_mutex>
std::map<std::string, std::string> data_;
// 可定时的共享互斥量
mutable std::shared_timed_mutex mutex_;  
// 读操作:多个线程可同时进行
std::string get(const std::string& key) const {
    std::shared_lock<std::shared_timed_mutex>\
    	lock(mutex_);
    auto it = data_.find(key);
    return it != data_.end() ? it->second : "";
}
// 写操作:独占访问
void set(const std::string& key, const std::string& value)
{
    std::unique_lock<std::shared_timed_mutex>
    	lock(mutex_);
    data_[key] = value;
}

// 超过1s没有获取到则放弃
std::unique_lock<std::shared_timed_mutex> 
	lock(mutex_, std::chrono::seconds(1));

(3) 算法模块:双范围算法

#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>

// 1. std::equal - 比较两个完整范围
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 3};
bool are_equal = std::equal(a.begin(), a.end(), 
                            b.begin(), b.end());  // 第二个范围完整指定
                            
// 2. std::mismatch - 查找第一个不同的位置
std::vector<int> c = {1, 2, 3, 4, 5};
std::vector<int> d = {1, 2, 3, 9, 10};
auto mismatch_pair = 
	std::mismatch(c.begin(), c.end(),
                  d.begin(), d.end());
if (mismatch_pair.first != c.end()) {
    std::cout << "First mismatch: " 
    		  << *mismatch_pair.first 
              << " vs " << *mismatch_pair.second 
              << std::endl;
}

// 3. 集合操作 - 更安全
std::vector<int> set1 = {1, 2, 3, 4, 5};
std::vector<int> set2 = {3, 4, 5, 6, 7};

// 交集
std::vector<int> intersection;
std::set_intersection(set1.begin(), set1.end(),
                      set2.begin(), set2.end(),
                      std::back_inserter(intersection));
// 差集
std::vector<int> difference;
std::set_difference(set1.begin(), set1.end(),
                    set2.begin(), set2.end(),
                    std::back_inserter(difference));
// 并集
std::vector<int> union_set;
std::set_union(set1.begin(), set1.end(),
               set2.begin(), set2.end(),
               std::back_inserter(union_set));

(4) 迭代器模块:全局迭代器函数

// 1. std::cbegin / std::cend - 获取const迭代器
std::vector<int> vec = {1, 2, 3, 4, 5};
// 等价于 vec.cbegin()
auto const_begin = std::cbegin(vec); 
// 等价于 vec.cend()
auto const_end = std::cend(vec);      
// 适用于原生数组
int arr[] = {1, 2, 3, 4, 5};
// const int*
auto arr_begin = std::cbegin(arr);    
auto arr_end = std::cend(arr);

// 2. std::rbegin/std::rend - 反向迭代器
auto reverse_begin = std::rbegin(vec);
auto reverse_end = std::rend(vec);

(5) 字符串模块

核心新增:std::quoted

// 转义输出
std::string text = R"(Hello "World" with quotes)";
std::cout << std::quoted(text) << std::endl;
// 输出: Hello "World" with quotes

3 C++17

C++17是一次重大更新,引入了许多新特性,进一步完善了现代C++。它侧重于简化代码、提高性能和增强标准库

3.1 核心语言特性模块

(1) 结构化绑定(Structured Bindings)

允许将结构体、数组或元组解包到多个变量中

#include <tuple>
#include <map>
#include <array>

// 1. 解包pair
std::pair<int, double> p{1, 3.14};
auto [x, y] = p;  // x=1, y=3.14

// 2. 解包tuple
std::tuple<int, double, std::string> 
	t{2, 2.71, "hello"};
// a=2, b=2.71, c="hello"
auto [a, b, c] = t;  

// 3. 解包数组
std::array<int, 3> arr{1, 2, 3};
auto [first, second, third] = arr;

// 4. 解包结构体
struct Point { int x; int y; };
Point pt{10, 20};
// px=10, py=20
auto [px, py] = pt;  

// 5. 在循环中使用
std::map<int, std::string> 
	m{{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) 
{
    std::cout << key << ": " 
    		  << value 
    		  << std::endl;
}

// 6. 与引用结合
auto& [rx, ry] = p;  // rx, ry是引用
// 修改p.first
rx = 42;  

// 7. 实际应用:函数返回多个值
std::tuple<int, double, bool> process_data()
{
    return {1, 2.5, true};
}

auto [id, value, success] =
	process_data();

(2) if constexpr - 编译时if

if constexpr 会在编译时「删掉」不满足条件的分支;

template<typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>) 
    {
     	// 如果是指针,解引用
        return *t; 
    } 
    else 
    {
   		// 否则直接返回
        return t;   
    }
}

(3) 内联变量(Inline Variables)

允许在头文件中定义变量而无需担心重复定义; 同一变量在多个编译单元中定义(只要内容一致),链接器会合并为单个实例

// C++17:内联变量
inline constexpr int MAX_SIZE = 1024;
inline const std::string DEFAULT_NAME = "default";
(4) 嵌套命名空间定义简化
// C++17之前
namespace A {
    namespace B {
        namespace C {
            void func() {}
        }
    }
}

// C++17:更简洁
namespace A::B::C {
    void func() {}
}

(5) using声明可以声明多个名称

// 1. 多个using声明
using std::cout, std::endl, std::string;

// 2. 在类中
class Base {
public:
    void func1() {}
    void func2() {}
};

class Derived : public Base {
public:
 	// 一次性引入多个
    using Base::func1, Base::func2; 
};

(6) 模板参数推导增强

类模板参数可以从构造函数推导

// 标准库容器推导
// 推导为vector<int>
std::vector v{1, 2, 3, 4, 5};           
// 推导为pair<int, double>
std::pair p{1, 3.14};      
// 推导为tuple<int, double, const char*>
std::tuple t{1, 2.5, "hello"};           

3.2 标准库模块

(1) std::optional - 可选值

#include <optional>
#include <iostream>

// 1. 基本用法
std::optional<int> find_value(int key) 
{
    if (key == 42) 
    {
        return 100;  // 返回值
    }
    return std::nullopt;  // 或无值
}
auto result = find_value(42);

// 如果有值返回它,否则返回-1
int value = result.value_or(-1); 

// 原地构造
std::optional<std::string> str;
// 直接构造,避免拷贝
str.emplace("Hello, World!");  

// 重置
str.reset();  // 设置为无值
str = std::nullopt;  // 等价

(2) std::variant - 类型安全的联合

可以存储多种类型中的一种

#include <variant>
#include <iostream>
#include <string>

// 1. 基本用法
std::variant<int, double, std::string> v;
// 存储int
v = 42;     
// 存储double
v = 3.14;      
// 存储const char*,转换为std::string
v = "hello";                

// 2. 访问值
try {
	// 如果当前不是int,抛出std::bad_variant_access
    int i = std::get<int>(v);  
    // 类似
    double d = std::get<double>(v);     
} 
catch (const std::bad_variant_access& e) 
{
    std::cout << "Wrong type!" << std::endl;
}

// 3. 安全访问
if (auto int_ptr = std::get_if<int>(&v)) 
{
    std::cout << "int: " 
    		  << *int_ptr 
    		  << std::endl;
}

// 4. 获取索引  
std::cout << "Index: " 
		  << v.index() //当前存储类型的索引
          << std::endl;  

// 5. 使用std::visit访问
auto visitor = [](auto&& arg) {
    using T = std::decay_t<decltype(arg)>;
    if constexpr(std::is_same_v<T, int>) 
    {
        std::cout << "int: " 
        		  << arg 
        		  << std::endl;
    }
    else if constexpr(std::is_same_v<T, double>) 
    {
        std::cout << "double: " 
        		  << arg 
        		  << std::endl;
    } 
    else if constexpr(std::is_same_v<T,std::string>) 
    {
        std::cout << "string: " 
        		  << arg 
        		  << std::endl;
    }
};

std::visit(visitor, v);

// 6. 实际应用:错误处理
std::variant<int, std::string> parse_input(const std::string& input) 
{
    try 
    {
        return std::stoi(input);
    }
    catch (...) 
    {
        return "Invalid input: "+input;
    }
}

// 7. 模拟多态,无需虚函数
struct Circle { double radius; };
struct Square { double side; };
struct Triangle { double base, height; };

using Shape = 
	std::variant<Circle, Square, Triangle>;

double area(const Shape& shape) {
    return 
    	std::visit([](auto&& s) 
        {
            using T = std::decay_t<decltype(s)>;
            if constexpr(std::is_same_v<T,Circle>) 
            {
                return 3.14*s.radius*s.radius;
            } 
            else if constexpr(std::is_same_v<T,Square>) 
            {
                return s.side*s.side;
            }
            else if constexpr(std::is_same_v<T,Triangle>) 
            {
                return 0.5*s.base*s.height;
            }
        }, shape);
}

(3) std::filesystem - 文件系统库

提供跨平台的文件和目录操作

#include <filesystem>
#include <iostream>
#include <vector>

namespace fs = std::filesystem;
// 1. 路径操作
fs::path p = "/usr/local/bin";
p /= "program";  // 追加路径
p += ".exe";     // 追加字符串

std::cout << "Path: " 
		  << p << std::endl;
std::cout << "Parent: " 
		  << p.parent_path() 
		  << std::endl;
std::cout << "Filename: " 
	      << p.filename() 
	      << std::endl;
std::cout << "Stem: " 
	      << p.stem() 
	      << std::endl;
std::cout << "Extension: " 
		  << p.extension() 
		  << std::endl;

// 2. 检查文件状态
if (fs::exists(p)) {
    std::cout << "Exists" << std::endl;

    if (fs::is_regular_file(p)) 
    {
        std::cout << "Regular file" 
        		  << std::endl;
        std::cout << "Size: " 
            	  << fs::file_size(p) 
            	  << " bytes" << std::endl;
    } 
    else if (fs::is_directory(p)) 
    {
        std::cout << "Directory" 
           		  << std::endl;
    }
}

// 3. 目录遍历
for (const auto& entry :
		fs::directory_iterator("."))
{
    std::cout << entry.path() << std::endl;
}

// 递归遍历
for (const auto& entry : fs::recursive_directory_iterator(".")) {
    if (entry.is_regular_file()) {
        std::cout << "File: " 
        		  << entry.path() 
                  << " (" 
                  << entry.file_size() 
                  << " bytes)" 
                  << std::endl;
    }
}

// 4. 文件操作
fs::create_directory("new_dir");
fs::copy_file("source.txt", 
			 "destination.txt", 
			 fs::copy_options::overwrite_existing);
fs::rename("old_name.txt",
		   "new_name.txt");
fs::remove("file_to_delete.txt");

// 5. 路径规范化
fs::path messy = 
		"/usr/../usr/local/./bin";

fs::path clean = 
	fs::canonical(messy); // /usr/local/bin

// 6. 临时文件/目录
fs::path temp_dir = 
		fs::temp_directory_path();
fs::path temp_file = 
		temp_dir / "temp.txt";

// 7. 文件权限
fs::perms perms =
		fs::status("file.txt").permissions();
bool owner_can_write = 
		(perms & fs::perms::owner_write)!= fs::perms::none;

(4) std::shared_mutex-简化的读写锁

C++14的shared_timed_mutex的简化版(没有定时功能)

// 基本用法
std::shared_mutex rw_mutex;
// 读操作:多个线程可同时进行
{
	// 共享锁
    std::shared_lock lock(rw_mutex);  
    // 读取数据...
}
// 写操作:独占访问
{
	// 独占锁
    std::unique_lock lock(rw_mutex);  
    // 修改数据...
}

(5) 并行算法

标准算法支持并行执行

#include <algorithm>
#include <execution>
#include <vector>
#include <iostream>
#include <chrono>
std::vector<int> data(10000000);
// 填充0-9999999
std::iota(data.begin(), data.end(), 0);  

// 1. 执行策略
// 顺序执行
auto seq = std::execution::seq;  
// 并行执行
auto par = std::execution::par; 
// 并行+向量化
auto par_unseq = std::execution::par_unseq;  

// 2. 并行排序
auto start =
	std::chrono::high_resolution_clock::now();
std::sort(par, data.begin(), data.end());
auto end = 
	std::chrono::high_resolution_clock::now();
auto duration = 
	std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Parallel sort: " << duration.count() << "ms" << std::endl;

// 3. 并行for_each
std::for_each(par,data.begin(),data.end(),[](int& x) 
{
	// 并行加倍所有元素
    x *= 2;  
});

// 4. 并行transform
std::vector<int> result(data.size());
std::transform(par, 
			   data.begin(), 
			   data.end(), 
			   result.begin(),
               [](int x) { return x * x; });

// 5. 并行reduce
int sum =
	std::reduce(par, data.begin(), data.end(), 0);
std::cout << "Sum: " << sum << std::endl;

// 6. 并行transform_reduce
double magnitude = std::transform_reduce(
    par,
    data.begin(), data.end(),
    0.0,
    std::plus<>(),
    [](int x){return static_cast<double>(x)*x;}
);

// 7. 并行查找
auto it = std::find(par, 
					data.begin(), 
					data.end(), 
					42);
if (it != data.end()) 
{
    std::cout << "Found 42 at position: " 
    		  << std::distance(data.begin(), it) 
    		  << std::endl;
}

// 8. 并行计数
size_t count = 
	std::count_if(par, 
				  data.begin(), 
				  data.end(),
				  [](int x){return x%2==0;});
std::cout << "Even numbers: " 
		  << count 
		  << std::endl;

不打无准备的仗,不打无把握的仗,要有把握,就要有准备,而且要有充分的准备…

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐