cpp-modern-features
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseModern C++ Features
现代C++特性
Modern C++ (C++11 and beyond) introduced significant improvements that make
C++ more expressive, safer, and easier to use. This skill covers essential
modern features including type inference, lambda expressions, range-based
loops, smart initialization, and the latest C++20 additions.
现代C++(C++11及后续版本)带来了重大改进,让C++代码更具表达力、更安全且更易用。本技能涵盖了核心的现代特性,包括类型推导、lambda表达式、范围for循环、智能初始化以及C++20的最新新增特性。
Auto Type Inference
auto类型推导
The keyword enables automatic type deduction, reducing verbosity while
maintaining type safety.
autocpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
void auto_examples() {
// Simple type inference
auto x = 42; // int
auto pi = 3.14159; // double
auto name = "Alice"; // const char*
auto message = std::string("Hello"); // std::string
// Iterator simplification
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Before C++11
for (std::vector<int>::iterator it = numbers.begin();
it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// With auto
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// Complex types
std::map<std::string, std::vector<int>> data;
auto it = data.find("key"); // Much cleaner than full type
// Return type deduction (C++14)
auto multiply = [](int a, int b) { return a * b; };
// Structured bindings (C++17)
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
}autocpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
void auto_examples() {
// Simple type inference
auto x = 42; // int
auto pi = 3.14159; // double
auto name = "Alice"; // const char*
auto message = std::string("Hello"); // std::string
// Iterator simplification
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Before C++11
for (std::vector<int>::iterator it = numbers.begin();
it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// With auto
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// Complex types
std::map<std::string, std::vector<int>> data;
auto it = data.find("key"); // Much cleaner than full type
// Return type deduction (C++14)
auto multiply = [](int a, int b) { return a * b; };
// Structured bindings (C++17)
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
}Lambda Expressions
Lambda表达式
Lambdas provide inline anonymous functions, essential for modern C++
algorithms and callbacks.
cpp
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
void lambda_examples() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// Basic lambda
auto print = [](int n) { std::cout << n << " "; };
std::for_each(numbers.begin(), numbers.end(), print);
// Lambda with capture
int threshold = 5;
auto above_threshold = [threshold](int n) { return n > threshold; };
// Capture by value [=]
auto sum_above = [=]() {
int sum = 0;
for (int n : numbers) {
if (n > threshold) sum += n;
}
return sum;
};
// Capture by reference [&]
int count = 0;
auto count_above = [&count, threshold](int n) {
if (n > threshold) count++;
};
std::for_each(numbers.begin(), numbers.end(), count_above);
// Generic lambda (C++14)
auto generic_print = [](const auto& item) {
std::cout << item << " ";
};
// Lambda as comparator
std::sort(numbers.begin(), numbers.end(),
[](int a, int b) { return a > b; }); // Descending
// Mutable lambda
auto counter = [count = 0]() mutable {
return ++count;
};
std::cout << counter() << "\n"; // 1
std::cout << counter() << "\n"; // 2
}
// Returning lambdas
std::function<int(int)> make_multiplier(int factor) {
return [factor](int n) { return n * factor; };
}Lambda表达式提供了内联匿名函数,是现代C++算法和回调函数的核心工具。
cpp
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
void lambda_examples() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// Basic lambda
auto print = [](int n) { std::cout << n << " "; };
std::for_each(numbers.begin(), numbers.end(), print);
// Lambda with capture
int threshold = 5;
auto above_threshold = [threshold](int n) { return n > threshold; };
// Capture by value [=]
auto sum_above = [=]() {
int sum = 0;
for (int n : numbers) {
if (n > threshold) sum += n;
}
return sum;
};
// Capture by reference [&]
int count = 0;
auto count_above = [&count, threshold](int n) {
if (n > threshold) count++;
};
std::for_each(numbers.begin(), numbers.end(), count_above);
// Generic lambda (C++14)
auto generic_print = [](const auto& item) {
std::cout << item << " ";
};
// Lambda as comparator
std::sort(numbers.begin(), numbers.end(),
[](int a, int b) { return a > b; }); // Descending
// Mutable lambda
auto counter = [count = 0]() mutable {
return ++count;
};
std::cout << counter() << "\n"; // 1
std::cout << counter() << "\n"; // 2
}
// Returning lambdas
std::function<int(int)> make_multiplier(int factor) {
return [factor](int n) { return n * factor; };
}Range-Based For Loops
范围for循环
Range-based for loops provide clean, safe iteration over containers and
ranges.
cpp
#include <vector>
#include <map>
#include <string>
#include <iostream>
void range_based_loops() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Basic iteration
for (int n : numbers) {
std::cout << n << " ";
}
// By reference (for modification)
for (int& n : numbers) {
n *= 2;
}
// By const reference (efficient for large objects)
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (const auto& name : names) {
std::cout << name << "\n";
}
// With structured bindings (C++17)
std::map<std::string, int> ages = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
for (const auto& [name, age] : ages) {
std::cout << name << " is " << age << " years old\n";
}
// Initializer in for loop (C++20)
for (std::vector<int> temp = {1, 2, 3}; auto n : temp) {
std::cout << n << " ";
}
}
// Custom range support
class Range {
int start_, end_;
public:
Range(int start, int end) : start_(start), end_(end) {}
struct Iterator {
int current;
Iterator(int val) : current(val) {}
int operator*() const { return current; }
Iterator& operator++() { ++current; return *this; }
bool operator!=(const Iterator& other) const {
return current != other.current;
}
};
Iterator begin() const { return Iterator(start_); }
Iterator end() const { return Iterator(end_); }
};
void use_custom_range() {
for (int i : Range(0, 10)) {
std::cout << i << " ";
}
}范围for循环提供了简洁、安全的容器和范围迭代方式。
cpp
#include <vector>
#include <map>
#include <string>
#include <iostream>
void range_based_loops() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Basic iteration
for (int n : numbers) {
std::cout << n << " ";
}
// By reference (for modification)
for (int& n : numbers) {
n *= 2;
}
// By const reference (efficient for large objects)
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (const auto& name : names) {
std::cout << name << "\n";
}
// With structured bindings (C++17)
std::map<std::string, int> ages = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
for (const auto& [name, age] : ages) {
std::cout << name << " is " << age << " years old\n";
}
// Initializer in for loop (C++20)
for (std::vector<int> temp = {1, 2, 3}; auto n : temp) {
std::cout << n << " ";
}
}
// Custom range support
class Range {
int start_, end_;
public:
Range(int start, int end) : start_(start), end_(end) {}
struct Iterator {
int current;
Iterator(int val) : current(val) {}
int operator*() const { return current; }
Iterator& operator++() { ++current; return *this; }
bool operator!=(const Iterator& other) const {
return current != other.current;
}
};
Iterator begin() const { return Iterator(start_); }
Iterator end() const { return Iterator(end_); }
};
void use_custom_range() {
for (int i : Range(0, 10)) {
std::cout << i << " ";
}
}Uniform Initialization
统一初始化
Uniform initialization using braces provides consistent syntax and prevents
narrowing conversions.
cpp
#include <vector>
#include <string>
#include <map>
struct Point {
int x, y;
};
void uniform_initialization() {
// Built-in types
int a{42};
double pi{3.14159};
// Containers
std::vector<int> numbers{1, 2, 3, 4, 5};
std::map<std::string, int> ages{
{"Alice", 30},
{"Bob", 25}
};
// Aggregates
Point p{10, 20};
// Prevents narrowing
// int x{3.14}; // Compiler error!
int x = 3.14; // Compiles (implicit conversion)
// Empty initialization (zero/default)
int zero{}; // 0
std::string empty{}; // ""
// Return value
auto get_numbers = []() { return std::vector<int>{1, 2, 3}; };
}
// Most vexing parse solution
class Widget {
public:
Widget() = default;
Widget(int x) {}
};
void vexing_parse() {
// Before C++11: declares a function!
// Widget w();
// Modern C++: creates an object
Widget w{}; // Correct
Widget w2{10}; // Also correct
}使用大括号的统一初始化提供了一致的语法,同时可以防止窄化转换。
cpp
#include <vector>
#include <string>
#include <map>
struct Point {
int x, y;
};
void uniform_initialization() {
// Built-in types
int a{42};
double pi{3.14159};
// Containers
std::vector<int> numbers{1, 2, 3, 4, 5};
std::map<std::string, int> ages{
{"Alice", 30},
{"Bob", 25}
};
// Aggregates
Point p{10, 20};
// Prevents narrowing
// int x{3.14}; // Compiler error!
int x = 3.14; // Compiles (implicit conversion)
// Empty initialization (zero/default)
int zero{}; // 0
std::string empty{}; // ""
// Return value
auto get_numbers = []() { return std::vector<int>{1, 2, 3}; };
}
// Most vexing parse solution
class Widget {
public:
Widget() = default;
Widget(int x) {}
};
void vexing_parse() {
// Before C++11: declares a function!
// Widget w();
// Modern C++: creates an object
Widget w{}; // Correct
Widget w2{10}; // Also correct
}Move Semantics and Rvalue References
移动语义与右值引用
Move semantics enable efficient transfer of resources without copying,
crucial for performance.
cpp
#include <vector>
#include <string>
#include <utility>
#include <iostream>
class Buffer {
size_t size_;
int* data_;
public:
// Constructor
Buffer(size_t size) : size_(size), data_(new int[size]) {
std::cout << "Constructor\n";
}
// Copy constructor
Buffer(const Buffer& other)
: size_(other.size_), data_(new int[other.size_]) {
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy constructor\n";
}
// Move constructor
Buffer(Buffer&& other) noexcept
: size_(other.size_), data_(other.data_) {
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move constructor\n";
}
// Copy assignment
Buffer& operator=(const Buffer& other) {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = new int[size_];
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy assignment\n";
}
return *this;
}
// Move assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = other.data_;
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move assignment\n";
}
return *this;
}
~Buffer() { delete[] data_; }
};
void move_semantics_example() {
Buffer b1(100);
Buffer b2 = std::move(b1); // Move, not copy
std::vector<Buffer> buffers;
buffers.push_back(Buffer(50)); // Move constructor used
// Perfect forwarding
auto make_buffer = [](auto&&... args) {
return Buffer(std::forward<decltype(args)>(args)...);
};
}移动语义支持无需复制即可高效转移资源,对性能提升至关重要。
cpp
#include <vector>
#include <string>
#include <utility>
#include <iostream>
class Buffer {
size_t size_;
int* data_;
public:
// Constructor
Buffer(size_t size) : size_(size), data_(new int[size]) {
std::cout << "Constructor\n";
}
// Copy constructor
Buffer(const Buffer& other)
: size_(other.size_), data_(new int[other.size_]) {
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy constructor\n";
}
// Move constructor
Buffer(Buffer&& other) noexcept
: size_(other.size_), data_(other.data_) {
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move constructor\n";
}
// Copy assignment
Buffer& operator=(const Buffer& other) {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = new int[size_];
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy assignment\n";
}
return *this;
}
// Move assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = other.data_;
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move assignment\n";
}
return *this;
}
~Buffer() { delete[] data_; }
};
void move_semantics_example() {
Buffer b1(100);
Buffer b2 = std::move(b1); // Move, not copy
std::vector<Buffer> buffers;
buffers.push_back(Buffer(50)); // Move constructor used
// Perfect forwarding
auto make_buffer = [](auto&&... args) {
return Buffer(std::forward<decltype(args)>(args)...);
};
}Variadic Templates
可变参数模板
Variadic templates enable functions and classes that accept any number of
arguments.
cpp
#include <iostream>
#include <string>
// Base case
void print() {
std::cout << "\n";
}
// Recursive variadic template
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...);
}
// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
template<typename... Args>
auto sum_with_init(Args... args) {
return (args + ... + 0);
}
// Perfect forwarding with variadic templates
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
void variadic_examples() {
print(1, 2.5, "hello", std::string("world"));
auto total = sum(1, 2, 3, 4, 5); // 15
// Fold expressions for various operations
auto all_true = [](auto... args) {
return (args && ...);
};
auto any_true = [](auto... args) {
return (args || ...);
};
}可变参数模板支持接受任意数量参数的函数和类。
cpp
#include <iostream>
#include <string>
// Base case
void print() {
std::cout << "\n";
}
// Recursive variadic template
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...);
}
// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
template<typename... Args>
auto sum_with_init(Args... args) {
return (args + ... + 0);
}
// Perfect forwarding with variadic templates
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
void variadic_examples() {
print(1, 2.5, "hello", std::string("world"));
auto total = sum(1, 2, 3, 4, 5); // 15
// Fold expressions for various operations
auto all_true = [](auto... args) {
return (args && ...);
};
auto any_true = [](auto... args) {
return (args || ...);
};
}Structured Bindings (C++17)
结构化绑定(C++17)
Structured bindings decompose objects into their constituent parts,
improving code readability.
cpp
#include <tuple>
#include <map>
#include <string>
#include <array>
struct Person {
std::string name;
int age;
double salary;
};
std::tuple<int, std::string, double> get_employee() {
return {42, "Alice", 75000.0};
}
void structured_bindings() {
// Tuple decomposition
auto [id, name, salary] = get_employee();
// Pair decomposition
std::pair<int, std::string> p{1, "one"};
auto [num, text] = p;
// Struct decomposition
Person person{"Bob", 30, 80000.0};
auto [pname, page, psalary] = person;
// Array decomposition
std::array<int, 3> arr{1, 2, 3};
auto [a, b, c] = arr;
// Map iteration
std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
// References
auto& [rname, rage, rsalary] = person;
rage = 31; // Modifies person.age
}结构化绑定可以将对象分解为其组成部分,提升代码可读性。
cpp
#include <tuple>
#include <map>
#include <string>
#include <array>
struct Person {
std::string name;
int age;
double salary;
};
std::tuple<int, std::string, double> get_employee() {
return {42, "Alice", 75000.0};
}
void structured_bindings() {
// Tuple decomposition
auto [id, name, salary] = get_employee();
// Pair decomposition
std::pair<int, std::string> p{1, "one"};
auto [num, text] = p;
// Struct decomposition
Person person{"Bob", 30, 80000.0};
auto [pname, page, psalary] = person;
// Array decomposition
std::array<int, 3> arr{1, 2, 3};
auto [a, b, c] = arr;
// Map iteration
std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
// References
auto& [rname, rage, rsalary] = person;
rage = 31; // Modifies person.age
}Concepts (C++20)
Concepts(C++20)
Concepts constrain template parameters, providing better error messages and
clearer interfaces.
cpp
#include <concepts>
#include <iostream>
#include <vector>
// Define custom concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// Use concept to constrain template
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// Concept with multiple constraints
template<typename T>
concept Printable = requires(T t) {
{ std::cout << t } -> std::convertible_to<std::ostream&>;
};
template<Printable T>
void print(const T& value) {
std::cout << value << "\n";
}
// Range concept
template<typename T>
concept Range = requires(T r) {
r.begin();
r.end();
};
template<Range R>
void print_range(const R& range) {
for (const auto& item : range) {
std::cout << item << " ";
}
std::cout << "\n";
}
// Concept with associated types
template<typename T>
concept Container = requires(T c) {
typename T::value_type;
typename T::iterator;
{ c.begin() } -> std::same_as<typename T::iterator>;
{ c.end() } -> std::same_as<typename T::iterator>;
{ c.size() } -> std::convertible_to<std::size_t>;
};
template<Container C>
void process_container(const C& container) {
std::cout << "Size: " << container.size() << "\n";
}
void concepts_example() {
auto result = add(5, 10); // OK
auto dresult = add(5.5, 2.3); // OK
// auto sresult = add("hi", "there"); // Error: doesn't satisfy
// Numeric
print(42);
print("Hello");
std::vector<int> vec{1, 2, 3};
print_range(vec);
process_container(vec);
}Concepts可以约束模板参数,提供更清晰的错误提示和更明确的接口。
cpp
#include <concepts>
#include <iostream>
#include <vector>
// Define custom concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// Use concept to constrain template
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// Concept with multiple constraints
template<typename T>
concept Printable = requires(T t) {
{ std::cout << t } -> std::convertible_to<std::ostream&>;
};
template<Printable T>
void print(const T& value) {
std::cout << value << "\n";
}
// Range concept
template<typename T>
concept Range = requires(T r) {
r.begin();
r.end();
};
template<Range R>
void print_range(const R& range) {
for (const auto& item : range) {
std::cout << item << " ";
}
std::cout << "\n";
}
// Concept with associated types
template<typename T>
concept Container = requires(T c) {
typename T::value_type;
typename T::iterator;
{ c.begin() } -> std::same_as<typename T::iterator>;
{ c.end() } -> std::same_as<typename T::iterator>;
{ c.size() } -> std::convertible_to<std::size_t>;
};
template<Container C>
void process_container(const C& container) {
std::cout << "Size: " << container.size() << "\n";
}
void concepts_example() {
auto result = add(5, 10); // OK
auto dresult = add(5.5, 2.3); // OK
// auto sresult = add("hi", "there"); // Error: doesn't satisfy
// Numeric
print(42);
print("Hello");
std::vector<int> vec{1, 2, 3};
print_range(vec);
process_container(vec);
}Ranges Library (C++20)
Ranges库(C++20)
The ranges library provides composable algorithms and views for working with
sequences.
cpp
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>
void ranges_examples() {
std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Views are lazy and composable
auto even = [](int n) { return n % 2 == 0; };
auto square = [](int n) { return n * n; };
// Compose operations without intermediate containers
auto result = numbers
| std::views::filter(even)
| std::views::transform(square)
| std::views::take(3);
for (int n : result) {
std::cout << n << " "; // 4 16 36
}
std::cout << "\n";
// Range algorithms
std::ranges::sort(numbers, std::greater{});
// Find with projection
struct Person {
std::string name;
int age;
};
std::vector<Person> people{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
auto it = std::ranges::find(people, "Bob", &Person::name);
// Views::iota for number generation
for (int i : std::views::iota(1, 6)) {
std::cout << i << " "; // 1 2 3 4 5
}
std::cout << "\n";
// Split view
std::string text = "one,two,three";
for (auto word : text | std::views::split(',')) {
for (char c : word) {
std::cout << c;
}
std::cout << " ";
}
}Ranges库提供了可组合的算法和视图,用于处理序列数据。
cpp
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>
void ranges_examples() {
std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Views are lazy and composable
auto even = [](int n) { return n % 2 == 0; };
auto square = [](int n) { return n * n; };
// Compose operations without intermediate containers
auto result = numbers
| std::views::filter(even)
| std::views::transform(square)
| std::views::take(3);
for (int n : result) {
std::cout << n << " "; // 4 16 36
}
std::cout << "\n";
// Range algorithms
std::ranges::sort(numbers, std::greater{});
// Find with projection
struct Person {
std::string name;
int age;
};
std::vector<Person> people{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
auto it = std::ranges::find(people, "Bob", &Person::name);
// Views::iota for number generation
for (int i : std::views::iota(1, 6)) {
std::cout << i << " "; // 1 2 3 4 5
}
std::cout << "\n";
// Split view
std::string text = "one,two,three";
for (auto word : text | std::views::split(',')) {
for (char c : word) {
std::cout << c;
}
std::cout << " ";
}
}Best Practices
最佳实践
- Use for complex types and iterators but keep simple types explicit
auto - Prefer lambdas over function objects for inline operations and callbacks
- Use range-based for loops instead of manual iterator manipulation
- Initialize variables with to prevent narrowing conversions
{} - Implement move constructors and assignments for resource-owning classes
- Use when transferring ownership, not for general optimization
std::move - Prefer structured bindings over for tuples and pairs
std::get<>() - Use concepts to constrain templates and improve error messages
- Leverage ranges for composable, lazy operations on sequences
- Use for range-based loops with large objects
const auto&
- 复杂类型和迭代器使用,但简单类型建议显式声明
auto - 内联操作和回调函数优先使用lambda表达式而非函数对象
- 使用范围for循环替代手动迭代器操作
- 使用初始化变量以防止窄化转换
{} - 为资源持有类实现移动构造函数和移动赋值运算符
- 转移所有权时使用,不要将其用于通用优化
std::move - 元组和pair优先使用结构化绑定而非
std::get<>() - 使用Concepts约束模板并改进错误提示
- 利用Ranges库实现可组合的惰性序列操作
- 处理大对象的范围for循环使用
const auto&
Common Pitfalls
常见陷阱
- Overusing making code less readable when types provide clarity
auto - Capturing by reference in lambdas that outlive their captures
- Using on const objects, which disables move semantics
std::move - Forgetting on move operations, preventing optimizations
noexcept - Modifying containers while iterating with range-based for loops
- Dangling references from structured bindings of temporary objects
- Using fold expressions without considering operator precedence
- Assuming ranges views create copies instead of providing lazy views
- Moving from objects that will be used again later
- Not marking move constructors and assignments as
noexcept
- 过度使用导致类型清晰性下降,降低代码可读性
auto - Lambda表达式中使用引用捕获,但捕获对象的生命周期短于Lambda
- 对const对象使用,这会禁用移动语义
std::move - 移动操作未标记,导致无法触发优化
noexcept - 使用范围for循环迭代时修改容器
- 对临时对象使用结构化绑定导致悬垂引用
- 使用折叠表达式时未考虑运算符优先级
- 误认为Ranges视图会创建副本,实际是惰性视图
- 移动对象后继续使用该对象
- 未将移动构造函数和移动赋值运算符标记为
noexcept
When to Use Modern C++ Features
何时使用现代C++特性
Use modern C++ features when you need:
- Cleaner, more expressive code with less boilerplate
- Better type safety with concepts and structured bindings
- Improved performance through move semantics
- Functional programming patterns with lambdas and ranges
- Generic programming with less template complexity
- Safer resource management with smart pointers
- Code that's easier to maintain and refactor
- Better compiler error messages with concepts
- Lazy evaluation and composition with ranges
- Migration from older C++ codebases to modern standards
在以下场景中使用现代C++特性:
- 需要更简洁、更具表达力且更少样板代码的实现
- 需要通过Concepts和结构化绑定提升类型安全性
- 需要通过移动语义提升性能
- 需要使用Lambda表达式和Ranges实现函数式编程模式
- 需要简化泛型编程的模板复杂度
- 需要更安全的资源管理(如智能指针)
- 需要更易于维护和重构的代码
- 需要通过Concepts获得更清晰的编译器错误提示
- 需要通过Ranges实现惰性求值和操作组合
- 需要从旧版C++代码库迁移到现代标准