C++ 现代特性
概述
现代C++(C++11及以后版本)引入了大量新特性,显著改善了语言的表达能力、安全性和性能。本章深入介绍C++11到C++23的重要特性,包括自动类型推导、智能指针、lambda表达式、移动语义、概念等。
🚀 C++11革命性特性
自动类型推导
cpp
#include <iostream>
#include <vector>
#include <map>
#include <memory>
void demonstrateAuto() {
// ✅ auto关键字
auto x = 42; // int
auto y = 3.14; // double
auto z = "Hello"; // const char*
auto str = std::string{"World"}; // std::string
// 复杂类型简化
std::vector<std::pair<int, std::string>> data;
// C++03方式(冗长)
for (std::vector<std::pair<int, std::string>>::iterator it = data.begin();
it != data.end(); ++it) {
// 处理 *it
}
// C++11方式(简洁)
for (auto it = data.begin(); it != data.end(); ++it) {
// 处理 *it
}
// 范围for循环
for (const auto& item : data) {
std::cout << item.first << ": " << item.second << std::endl;
}
// lambda表达式中的auto
auto lambda = [](auto x, auto y) { return x + y; };
std::cout << lambda(1, 2) << std::endl; // int
std::cout << lambda(1.5, 2.5) << std::endl; // double
}
// ✅ decltype关键字
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) { // C++11返回类型后置
return t + u;
}
// C++14简化版本
template<typename T, typename U>
auto add_simple(T t, U u) {
return t + u;
}
// decltype用法
void demonstrateDecltype() {
int x = 10;
decltype(x) y = 20; // y的类型是int
const int& ref = x;
decltype(ref) z = x; // z的类型是const int&
// 用于模板编程
std::vector<int> vec;
decltype(vec.size()) size = vec.size(); // size_t类型
}Lambda表达式
cpp
#include <algorithm>
#include <functional>
#include <vector>
class LambdaDemo {
public:
void demonstrateLambda() {
std::vector<int> numbers{5, 2, 8, 1, 9};
// ✅ 基本lambda语法
auto print = [](int x) { std::cout << x << " "; };
std::for_each(numbers.begin(), numbers.end(), print);
// ✅ 捕获列表
int threshold = 5;
// 按值捕获
auto greater_than_threshold = [threshold](int x) {
return x > threshold;
};
// 按引用捕获
int count = 0;
auto counter = [&count](int x) {
if (x > 5) ++count;
};
std::for_each(numbers.begin(), numbers.end(), counter);
std::cout << "Count: " << count << std::endl;
// ✅ 捕获所有
auto lambda_all_by_value = [=]() {
return threshold + count; // 所有外部变量按值捕获
};
auto lambda_all_by_ref = [&]() {
++count; // 所有外部变量按引用捕获
return threshold;
};
// ✅ 混合捕获
auto mixed_capture = [&count, threshold](int x) {
if (x > threshold) ++count;
};
// ✅ 可变lambda
auto mutable_lambda = [count](int x) mutable {
++count; // 修改按值捕获的变量副本
return count + x;
};
// ✅ 递归lambda
std::function<int(int)> factorial = [&factorial](int n) -> int {
return (n <= 1) ? 1 : n * factorial(n - 1);
};
std::cout << "5! = " << factorial(5) << std::endl;
}
// ✅ lambda作为函数参数
template<typename Predicate>
void processIf(const std::vector<int>& data, Predicate pred) {
for (const auto& item : data) {
if (pred(item)) {
std::cout << item << " passed test" << std::endl;
}
}
}
void useLambdaAsParameter() {
std::vector<int> data{1, 2, 3, 4, 5};
processIf(data, [](int x) { return x % 2 == 0; }); // 偶数
processIf(data, [](int x) { return x > 3; }); // 大于3
}
};智能指针
cpp
#include <memory>
#include <iostream>
class Resource {
public:
Resource(int id) : id_(id) {
std::cout << "Resource " << id_ << " created" << std::endl;
}
~Resource() {
std::cout << "Resource " << id_ << " destroyed" << std::endl;
}
void use() {
std::cout << "Using resource " << id_ << std::endl;
}
int getId() const { return id_; }
private:
int id_;
};
void demonstrateSmartPointers() {
// ✅ unique_ptr - 独占所有权
std::unique_ptr<Resource> unique_res = std::make_unique<Resource>(1);
unique_res->use();
// 转移所有权
std::unique_ptr<Resource> moved_res = std::move(unique_res);
// unique_res现在为nullptr
if (moved_res) {
moved_res->use();
}
// ✅ shared_ptr - 共享所有权
std::shared_ptr<Resource> shared_res1 = std::make_shared<Resource>(2);
std::cout << "Reference count: " << shared_res1.use_count() << std::endl;
{
std::shared_ptr<Resource> shared_res2 = shared_res1;
std::cout << "Reference count: " << shared_res1.use_count() << std::endl;
shared_res2->use();
} // shared_res2析构,引用计数减1
std::cout << "Reference count: " << shared_res1.use_count() << std::endl;
// ✅ weak_ptr - 避免循环引用
std::weak_ptr<Resource> weak_res = shared_res1;
if (auto locked = weak_res.lock()) { // 尝试获取shared_ptr
locked->use();
std::cout << "Resource is still alive" << std::endl;
}
shared_res1.reset(); // 释放资源
if (weak_res.expired()) {
std::cout << "Resource has been destroyed" << std::endl;
}
}
// ✅ 自定义删除器
void demonstrateCustomDeleter() {
auto custom_deleter = [](Resource* res) {
std::cout << "Custom deleter called for resource " << res->getId() << std::endl;
delete res;
};
std::unique_ptr<Resource, decltype(custom_deleter)> res(
new Resource(99), custom_deleter);
// C数组的智能指针
std::unique_ptr<int[]> arr = std::make_unique<int[]>(10);
for (int i = 0; i < 10; ++i) {
arr[i] = i * i;
}
}移动语义
cpp
#include <vector>
#include <string>
#include <utility>
class MoveableResource {
private:
std::vector<int> data_;
std::string name_;
public:
// 构造函数
MoveableResource(const std::string& name, size_t size)
: name_(name), data_(size, 0) {
std::cout << "Constructor: " << name_ << std::endl;
}
// ✅ 拷贝构造函数
MoveableResource(const MoveableResource& other)
: name_(other.name_), data_(other.data_) {
std::cout << "Copy constructor: " << name_ << std::endl;
}
// ✅ 移动构造函数
MoveableResource(MoveableResource&& other) noexcept
: name_(std::move(other.name_)), data_(std::move(other.data_)) {
std::cout << "Move constructor: " << name_ << std::endl;
}
// ✅ 拷贝赋值运算符
MoveableResource& operator=(const MoveableResource& other) {
if (this != &other) {
name_ = other.name_;
data_ = other.data_;
std::cout << "Copy assignment: " << name_ << std::endl;
}
return *this;
}
// ✅ 移动赋值运算符
MoveableResource& operator=(MoveableResource&& other) noexcept {
if (this != &other) {
name_ = std::move(other.name_);
data_ = std::move(other.data_);
std::cout << "Move assignment: " << name_ << std::endl;
}
return *this;
}
~MoveableResource() {
std::cout << "Destructor: " << name_ << std::endl;
}
const std::string& getName() const { return name_; }
size_t size() const { return data_.size(); }
};
// ✅ 完美转发
template<typename T>
void wrapper(T&& arg) {
process(std::forward<T>(arg)); // 完美转发
}
void process(const MoveableResource& res) {
std::cout << "Processing lvalue: " << res.getName() << std::endl;
}
void process(MoveableResource&& res) {
std::cout << "Processing rvalue: " << res.getName() << std::endl;
}
void demonstrateMoveSematics() {
// 拷贝
MoveableResource res1("Resource1", 1000);
MoveableResource res2 = res1; // 拷贝构造
// 移动
MoveableResource res3 = std::move(res1); // 移动构造
// res1现在处于有效但未指定状态
std::cout << "res1 name after move: '" << res1.getName() << "'" << std::endl;
// 函数返回值优化(RVO)
auto createResource = []() {
return MoveableResource("TempResource", 500);
};
MoveableResource res4 = createResource(); // 可能触发移动或RVO
// 完美转发测试
MoveableResource res5("ForwardTest", 100);
wrapper(res5); // 左值引用
wrapper(std::move(res5)); // 右值引用
wrapper(MoveableResource("Temp", 50)); // 临时对象
}🔧 C++14增强特性
auto和lambda改进
cpp
#include <iostream>
#include <vector>
#include <algorithm>
void demonstrateCpp14Features() {
// ✅ auto返回类型推导
auto multiply = [](auto x, auto y) {
return x * y; // 返回类型自动推导
};
std::cout << multiply(3, 4) << std::endl; // int
std::cout << multiply(2.5, 3.0) << std::endl; // double
// ✅ 泛型lambda
auto process = [](auto&& container) {
using T = std::decay_t<decltype(container)>;
std::cout << "Processing container of size: " << container.size() << std::endl;
std::for_each(container.begin(), container.end(), [](const auto& item) {
std::cout << item << " ";
});
std::cout << std::endl;
};
std::vector<int> numbers{1, 2, 3, 4, 5};
std::vector<std::string> words{"hello", "world"};
process(numbers);
process(words);
// ✅ 初始化捕获
auto counter = [count = 0](int increment) mutable {
count += increment;
return count;
};
std::cout << counter(5) << std::endl; // 5
std::cout << counter(3) << std::endl; // 8
// ✅ 移动捕获
auto data = std::make_unique<std::vector<int>>(10, 42);
auto lambda_with_move = [captured_data = std::move(data)](int index) {
if (index < captured_data->size()) {
return (*captured_data)[index];
}
return -1;
};
std::cout << lambda_with_move(5) << std::endl; // 42
}
// ✅ 变量模板(C++14)
template<typename T>
constexpr T pi = T(3.1415926535897932385);
void demonstrateVariableTemplates() {
std::cout << "pi<float>: " << pi<float> << std::endl;
std::cout << "pi<double>: " << pi<double> << std::endl;
std::cout << "pi<long double>: " << pi<long double> << std::endl;
}🎯 C++17实用特性
结构化绑定
cpp
#include <tuple>
#include <map>
#include <string>
void demonstrateStructuredBindings() {
// ✅ tuple解包
auto getData() {
return std::make_tuple(42, "Hello", 3.14);
}
auto [id, message, value] = getData();
std::cout << id << ", " << message << ", " << value << std::endl;
// ✅ pair解包
std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << std::endl;
}
// ✅ 数组解包
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;
std::cout << a << ", " << b << ", " << c << std::endl;
// ✅ 自定义类型
struct Point {
int x, y;
};
Point p{10, 20};
auto [x, y] = p;
std::cout << "Point: (" << x << ", " << y << ")" << std::endl;
}
// ✅ if constexpr
template<typename T>
void processValue(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Processing integer: " << value << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "Processing floating point: " << value << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Processing string: " << value << std::endl;
} else {
std::cout << "Processing unknown type" << std::endl;
}
}
// ✅ std::optional
#include <optional>
std::optional<int> divide(int a, int b) {
if (b != 0) {
return a / b;
}
return std::nullopt;
}
void demonstrateOptional() {
auto result = divide(10, 2);
if (result) {
std::cout << "Result: " << *result << std::endl;
}
auto invalid = divide(10, 0);
if (!invalid) {
std::cout << "Division by zero!" << std::endl;
}
// 使用value_or提供默认值
std::cout << "Safe result: " << invalid.value_or(-1) << std::endl;
}
// ✅ std::variant
#include <variant>
void demonstrateVariant() {
std::variant<int, std::string, double> data;
data = 42;
std::cout << "Holds int: " << std::get<int>(data) << std::endl;
data = std::string("Hello");
std::cout << "Holds string: " << std::get<std::string>(data) << std::endl;
data = 3.14;
std::cout << "Holds double: " << std::get<double>(data) << std::endl;
// 访问者模式
std::visit([](const auto& value) {
std::cout << "Visiting: " << value << std::endl;
}, data);
// 类型安全访问
if (std::holds_alternative<double>(data)) {
std::cout << "Currently holds double" << std::endl;
}
}🔥 C++20革命性特性
概念 (Concepts)
cpp
#include <concepts>
#include <iostream>
#include <vector>
// ✅ 标准概念
template<std::integral T>
void processInteger(T value) {
std::cout << "Processing integer: " << value << std::endl;
}
template<std::floating_point T>
void processFloat(T value) {
std::cout << "Processing float: " << value << std::endl;
}
// ✅ 自定义概念
template<typename T>
concept Printable = requires(T t) {
std::cout << t;
};
template<typename T>
concept Container = requires(T t) {
typename T::value_type;
typename T::iterator;
t.begin();
t.end();
t.size();
};
template<Container T>
void printContainer(const T& container) {
std::cout << "Container size: " << container.size() << std::endl;
for (const auto& item : container) {
std::cout << item << " ";
}
std::cout << std::endl;
}
// ✅ 复杂概念
template<typename T>
concept Comparable = requires(T a, T b) {
{ a == b } -> std::convertible_to<bool>;
{ a != b } -> std::convertible_to<bool>;
{ a < b } -> std::convertible_to<bool>;
};
template<Comparable T>
T findMax(const std::vector<T>& data) {
if (data.empty()) {
throw std::invalid_argument("Empty container");
}
T max_val = data[0];
for (const auto& item : data) {
if (item > max_val) {
max_val = item;
}
}
return max_val;
}
void demonstrateConcepts() {
processInteger(42);
processFloat(3.14);
std::vector<int> numbers{1, 2, 3, 4, 5};
printContainer(numbers);
auto max_num = findMax(numbers);
std::cout << "Max: " << max_num << std::endl;
}协程 (Coroutines)
cpp
#include <coroutine>
#include <iostream>
#include <exception>
// ✅ 简单生成器
template<typename T>
struct Generator {
struct promise_type {
T current_value;
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value) {
current_value = value;
return {};
}
void return_void() {}
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> coro;
Generator(std::coroutine_handle<promise_type> h) : coro(h) {}
~Generator() {
if (coro) {
coro.destroy();
}
}
// 迭代器接口
struct iterator {
std::coroutine_handle<promise_type> coro;
bool done;
iterator(std::coroutine_handle<promise_type> h, bool is_done)
: coro(h), done(is_done) {}
T operator*() const { return coro.promise().current_value; }
iterator& operator++() {
coro.resume();
done = coro.done();
return *this;
}
bool operator==(const iterator& other) const {
return done == other.done;
}
};
iterator begin() {
if (coro) {
coro.resume();
return iterator{coro, coro.done()};
}
return iterator{nullptr, true};
}
iterator end() {
return iterator{nullptr, true};
}
};
// ✅ 斐波那契数列生成器
Generator<int> fibonacci(int count) {
int a = 0, b = 1;
for (int i = 0; i < count; ++i) {
co_yield a;
auto temp = a + b;
a = b;
b = temp;
}
}
void demonstrateCoroutines() {
std::cout << "Fibonacci sequence:" << std::endl;
for (int value : fibonacci(10)) {
std::cout << value << " ";
}
std::cout << std::endl;
}模块 (Modules)
cpp
// ✅ 模块定义文件 math_module.cpp
/*
export module math_utils;
export namespace math {
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
template<typename T>
T power(T base, int exponent) {
T result = 1;
for (int i = 0; i < exponent; ++i) {
result *= base;
}
return result;
}
}
// 内部实现(不导出)
namespace {
int internal_helper(int x) {
return x * 2;
}
}
*/
// ✅ 使用模块
/*
import math_utils;
#include <iostream>
int main() {
std::cout << math::add(2, 3) << std::endl;
std::cout << math::multiply(4, 5) << std::endl;
std::cout << math::power(2, 8) << std::endl;
return 0;
}
*/🌟 C++23新特性预览
改进的范围算法
cpp
#include <ranges>
#include <vector>
#include <algorithm>
#include <iostream>
void demonstrateRanges() {
std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// ✅ 范围视图组合
auto even_squares = numbers
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });
std::cout << "Even squares: ";
for (int value : even_squares) {
std::cout << value << " ";
}
std::cout << std::endl;
// ✅ 范围算法
std::vector<int> sorted_data = numbers;
std::ranges::sort(sorted_data, std::greater{});
std::cout << "Sorted (descending): ";
std::ranges::copy(sorted_data, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// ✅ 投影
std::vector<std::string> words{"hello", "world", "cpp", "modern"};
// 按长度排序
std::ranges::sort(words, {}, &std::string::size);
std::cout << "Sorted by length: ";
for (const auto& word : words) {
std::cout << word << " ";
}
std::cout << std::endl;
}
// ✅ std::expected (C++23)
#include <expected>
std::expected<int, std::string> divide_safe(int a, int b) {
if (b == 0) {
return std::unexpected{"Division by zero"};
}
return a / b;
}
void demonstrateExpected() {
auto result1 = divide_safe(10, 2);
if (result1) {
std::cout << "Result: " << *result1 << std::endl;
}
auto result2 = divide_safe(10, 0);
if (!result2) {
std::cout << "Error: " << result2.error() << std::endl;
}
}总结
C++现代特性时间线
| 版本 | 关键特性 | 影响 |
|---|---|---|
| C++11 | auto, lambda, 智能指针, 移动语义 | 革命性变化 |
| C++14 | 泛型lambda, auto返回类型 | 增量改进 |
| C++17 | 结构化绑定, if constexpr, optional | 实用性提升 |
| C++20 | 概念, 协程, 模块, 范围 | 下一代特性 |
| C++23 | expected, 改进的范围 | 持续演进 |
采用建议
- 立即使用: auto, lambda, 智能指针, 范围for
- 积极采用: 结构化绑定, optional, variant
- 谨慎尝试: 协程, 模块(工具链支持)
- 关注发展: 概念, 范围算法
学习路径
- 基础: auto, lambda, 智能指针
- 进阶: 移动语义, 完美转发
- 现代: 概念, 协程, 模块
- 未来: 持续关注标准发展
最佳实践
- 渐进式采用: 不要一次性使用所有新特性
- 团队一致: 建立团队的现代C++使用规范
- 工具支持: 确保编译器和工具链支持
- 性能意识: 新特性不等于更好的性能
- 可读性优先: 代码清晰比使用新特性更重要
现代C++特性极大地改善了语言的表达能力和安全性,但需要循序渐进地学习和采用。关键是理解每个特性的适用场景,在合适的时候使用合适的特性。