C++标准详细介绍:C++11/C++14/C++17
前言
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;
不打无准备的仗,不打无把握的仗,要有把握,就要有准备,而且要有充分的准备…
更多推荐


所有评论(0)