第37章 特殊工具和技术

C++20新特性:位操作库

C++20引入了<bit>库,提供了一系列用于位操作的函数:

位操作库的基本功能

  • 位计数:计算置位的位数
  • 位查找:查找第一个或最后一个置位的位置
  • 位操作:设置、清除、翻转位
  • 位旋转:循环移位操作

位操作库的使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bit>
#include <iostream>
#include <cstdint>

int main() {
uint8_t value = 0b10101010;

// 位计数
int count = std::popcount(value);
std::cout << "Number of set bits: " << count << std::endl; // 输出:4

// 位查找
int first_set = std::countr_zero(value); // 从右数第一个置位的位置(0-based)
std::cout << "First set bit position: " << first_set << std::endl; // 输出:1

int last_set = std::countl_zero(value); // 从左数第一个置位的位置(0-based)
std::cout << "Leading zeros: " << last_set << std::endl; // 输出:0

// 位操作
uint8_t set_bit = std::setbit(value, 2); // 设置第2位
std::cout << "After setting bit 2: " << static_cast<int>(set_bit) << std::endl;

uint8_t clear_bit = std::clearbit(value, 1); // 清除第1位
std::cout << "After clearing bit 1: " << static_cast<int>(clear_bit) << std::endl;

uint8_t flip_bit = std::flipbit(value, 0); // 翻转第0位
std::cout << "After flipping bit 0: " << static_cast<int>(flip_bit) << std::endl;

// 位旋转
uint8_t rotate_left = std::rotl(value, 1); // 左旋转1位
std::cout << "After left rotation: " << static_cast<int>(rotate_left) << std::endl;

uint8_t rotate_right = std::rotr(value, 1); // 右旋转1位
std::cout << "After right rotation: " << static_cast<int>(rotate_right) << std::endl;

// 其他位操作
bool is_power_of_two = std::has_single_bit(8); // 检查是否是2的幂
std::cout << "8 is power of two: " << std::boolalpha << is_power_of_two << std::endl; // true

uint8_t next_power_of_two = std::bit_ceil(10); // 大于等于10的最小2的幂
std::cout << "Next power of two after 10: " << static_cast<int>(next_power_of_two) << std::endl; // 16

return 0;
}

位操作库的优点

  1. 标准化:提供了跨平台一致的位操作接口
  2. 优化:实现经过了编译器优化,性能优异
  3. 可读性:使用命名函数替代位掩码,提高代码可读性
  4. 安全性:避免了手动位操作的常见错误
  5. 完整性:提供了全面的位操作功能

类型转换运算符

static_cast

static_cast用于相关类型之间的转换,是最常用的类型转换运算符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

int main() {
// 基本类型转换
double d = 3.14;
int i = static_cast<int>(d);
std::cout << "double to int: " << i << std::endl;

// 指针转换(相关类型)
class Base { public: virtual ~Base() {} };
class Derived : public Base { public: void foo() { std::cout << "Derived::foo()" << std::endl; } };

Base* basePtr = new Derived();
Derived* derivedPtr = static_cast<Derived*>(basePtr); // 向上转换,安全
derivedPtr->foo();

delete basePtr;

// 引用转换
Derived derived;
Base& baseRef = derived;
Derived& derivedRef = static_cast<Derived&>(baseRef);
derivedRef.foo();

return 0;
}

dynamic_cast

dynamic_cast用于多态类型之间的转换,运行时检查类型安全性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>

int main() {
class Base { public: virtual ~Base() {} };
class Derived : public Base { public: void foo() { std::cout << "Derived::foo()" << std::endl; } };
class AnotherDerived : public Base { public: void bar() { std::cout << "AnotherDerived::bar()" << std::endl; } };

// 向上转换(安全)
Base* basePtr1 = new Derived();

// 向下转换(运行时检查)
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr1);
if (derivedPtr) {
derivedPtr->foo(); // 成功
}

AnotherDerived* anotherDerivedPtr = dynamic_cast<AnotherDerived*>(basePtr1);
if (anotherDerivedPtr) {
anotherDerivedPtr->bar(); // 不会执行
} else {
std::cout << "dynamic_cast failed: not an AnotherDerived" << std::endl;
}

// 引用转换(失败时抛出异常)
try {
Base& baseRef = *basePtr1;
AnotherDerived& anotherDerivedRef = dynamic_cast<AnotherDerived&>(baseRef);
anotherDerivedRef.bar();
} catch (const std::bad_cast& e) {
std::cout << "dynamic_cast failed: " << e.what() << std::endl;
}

delete basePtr1;

return 0;
}

const_cast

const_cast用于添加或删除const限定符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

void func(int* ptr) {
*ptr = 100;
}

int main() {
// 删除const
const int x = 42;
int* nonConstPtr = const_cast<int*>(&x);
*nonConstPtr = 100; // 未定义行为:修改const变量
std::cout << "x: " << x << std::endl; // 可能仍然输出42

// 添加const
int y = 42;
const int* constPtr = const_cast<const int*>(&y);
// *constPtr = 100; // 错误:不能修改const指针指向的值

// 函数参数转换
const int z = 42;
func(const_cast<int*>(&z)); // 危险:函数可能修改const变量

return 0;
}

reinterpret_cast

reinterpret_cast用于不相关类型之间的转换,是最危险的类型转换运算符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

int main() {
// 指针类型转换
int x = 100;
int* intPtr = &x;
void* voidPtr = reinterpret_cast<void*>(intPtr);
int* convertedPtr = reinterpret_cast<int*>(voidPtr);
std::cout << "*convertedPtr: " << *convertedPtr << std::endl;

// 整数和指针之间的转换
uintptr_t intValue = reinterpret_cast<uintptr_t>(intPtr);
std::cout << "Pointer as integer: " << intValue << std::endl;
int* ptrFromInt = reinterpret_cast<int*>(intValue);
std::cout << "*ptrFromInt: " << *ptrFromInt << std::endl;

// 不同类型的指针转换
double d = 3.14;
double* doublePtr = &d;
int* intPtr2 = reinterpret_cast<int*>(doublePtr);
// std::cout << "*intPtr2: " << *intPtr2 << std::endl; // 未定义行为

return 0;
}

运行时类型识别(RTTI)

RTTI允许在运行时确定对象的类型,主要通过typeid运算符和dynamic_cast实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <typeinfo>

int main() {
// 基本类型
int i = 42;
double d = 3.14;
std::string s = "hello";

std::cout << "Type of i: " << typeid(i).name() << std::endl;
std::cout << "Type of d: " << typeid(d).name() << std::endl;
std::cout << "Type of s: " << typeid(s).name() << std::endl;

// 类型比较
if (typeid(i) == typeid(int)) {
std::cout << "i is an int" << std::endl;
}

// 多态类型
class Base { public: virtual ~Base() {} };
class Derived : public Base {};

Base* basePtr = new Derived();
std::cout << "Type of *basePtr: " << typeid(*basePtr).name() << std::endl; // 输出Derived类型

Base baseObj;
std::cout << "Type of baseObj: " << typeid(baseObj).name() << std::endl; // 输出Base类型

delete basePtr;

return 0;
}

异常处理

基本异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <stdexcept>

void divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("Division by zero");
}
std::cout << "Result: " << static_cast<double>(a) / b << std::endl;
}

int main() {
try {
divide(10, 2);
divide(10, 0); // 抛出异常
} catch (const std::exception& e) {
std::cout << "Exception caught: " << e.what() << std::endl;
} catch (...) {
std::cout << "Unknown exception caught" << std::endl;
}

return 0;
}

自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <stdexcept>

class MyException : public std::exception {
private:
std::string message;

public:
MyException(const std::string& msg) : message(msg) {}

const char* what() const noexcept override {
return message.c_str();
}
};

void validateAge(int age) {
if (age < 0) {
throw MyException("Age cannot be negative");
}
if (age > 120) {
throw MyException("Age is out of range");
}
std::cout << "Valid age: " << age << std::endl;
}

int main() {
try {
validateAge(25);
validateAge(-5); // 抛出异常
} catch (const MyException& e) {
std::cout << "MyException caught: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "std::exception caught: " << e.what() << std::endl;
}

return 0;
}

异常规格说明(C++11前)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

// 异常规格说明(已废弃,C++11起使用noexcept)
void func() throw(int, double) {
// 可能抛出int或double类型的异常
throw 42;
}

void noThrowFunc() throw() {
// 不抛出任何异常
}

int main() {
try {
func();
} catch (int e) {
std::cout << "Caught int: " << e << std::endl;
}

return 0;
}

noexcept说明符(C++11+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

// 不抛出任何异常
void noThrowFunc() noexcept {
std::cout << "noThrowFunc()" << std::endl;
}

// 条件性noexcept
void conditionalNoThrowFunc(bool throwException) noexcept(noexcept(throwException)) {
if (throwException) {
// 注意:虽然声明了noexcept,但如果这里抛出异常,会调用std::terminate
// throw std::runtime_error("Error");
}
std::cout << "conditionalNoThrowFunc()" << std::endl;
}

// 检查函数是否noexcept
template<typename T>
void checkNoexcept() {
std::cout << "std::is_nothrow_invocable_v<T()>: " << std::is_nothrow_invocable_v<T()>() << std::endl;
}

int main() {
noThrowFunc();
conditionalNoThrowFunc(false);

return 0;
}

内存管理

智能指针(C++11+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <memory>

class MyClass {
private:
int value;

public:
MyClass(int v) : value(v) {
std::cout << "MyClass constructed: " << value << std::endl;
}

~MyClass() {
std::cout << "MyClass destructed: " << value << std::endl;
}

void foo() {
std::cout << "MyClass::foo(): " << value << std::endl;
}
};

int main() {
// unique_ptr:独占所有权
std::cout << "=== unique_ptr ===" << std::endl;
std::unique_ptr<MyClass> uptr1(new MyClass(1));
uptr1->foo();

// 转移所有权
std::unique_ptr<MyClass> uptr2 = std::move(uptr1);
// uptr1->foo(); // 错误:uptr1已失去所有权
uptr2->foo();

// shared_ptr:共享所有权
std::cout << "\n=== shared_ptr ===" << std::endl;
std::shared_ptr<MyClass> sptr1(new MyClass(2));
std::cout << "Reference count: " << sptr1.use_count() << std::endl;

{
std::shared_ptr<MyClass> sptr2 = sptr1;
std::cout << "Reference count: " << sptr1.use_count() << std::endl;
sptr2->foo();
}

std::cout << "Reference count: " << sptr1.use_count() << std::endl;
sptr1->foo();

// weak_ptr:不增加引用计数的shared_ptr观察者
std::cout << "\n=== weak_ptr ===" << std::endl;
std::weak_ptr<MyClass> wptr = sptr1;
std::cout << "Reference count: " << sptr1.use_count() << std::endl;

if (auto locked = wptr.lock()) {
locked->foo();
}

// 重置shared_ptr
sptr1.reset();
std::cout << "Reference count after reset: " << (wptr.expired() ? "0 (expired)" : "non-zero") << std::endl;

// make_unique和make_shared(推荐)
std::cout << "\n=== make_unique and make_shared ===" << std::endl;
auto uptr3 = std::make_unique<MyClass>(3);
auto sptr3 = std::make_shared<MyClass>(4);

uptr3->foo();
sptr3->foo();

return 0;
}

内存池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <vector>

class MemoryPool {
private:
std::vector<void*> blocks;
size_t blockSize;
size_t capacity;
size_t used;

public:
MemoryPool(size_t blockSize, size_t capacity) : blockSize(blockSize), capacity(capacity), used(0) {
blocks.reserve(capacity);
for (size_t i = 0; i < capacity; ++i) {
blocks.push_back(std::malloc(blockSize));
}
}

~MemoryPool() {
for (void* block : blocks) {
std::free(block);
}
}

void* allocate() {
if (used < capacity) {
return blocks[used++];
}
// 可以选择扩展容量或返回nullptr
return nullptr;
}

void deallocate(void* ptr) {
// 简单实现:将ptr放回池中(实际应用中需要更复杂的管理)
for (size_t i = 0; i < used; ++i) {
if (blocks[i] == ptr) {
// 交换到最后位置
std::swap(blocks[i], blocks[--used]);
break;
}
}
}

size_t getUsed() const {
return used;
}

size_t getCapacity() const {
return capacity;
}
};

int main() {
MemoryPool pool(sizeof(int), 10);

// 分配内存
int* ptrs[5];
for (int i = 0; i < 5; ++i) {
ptrs[i] = static_cast<int*>(pool.allocate());
*ptrs[i] = i * 10;
std::cout << "Allocated: " << *ptrs[i] << std::endl;
}

std::cout << "Used: " << pool.getUsed() << "/" << pool.getCapacity() << std::endl;

// 释放内存
pool.deallocate(ptrs[2]);
std::cout << "After deallocating ptrs[2]: " << pool.getUsed() << "/" << pool.getCapacity() << std::endl;

// 重新分配
int* newPtr = static_cast<int*>(pool.allocate());
*newPtr = 99;
std::cout << "Reallocated: " << *newPtr << std::endl;
std::cout << "Used: " << pool.getUsed() << "/" << pool.getCapacity() << std::endl;

return 0;
}

元编程

模板特化

1
2
3
4
5
6
#include <iostream>

// 主模板
template<typename T>
class MyClass {
publ

继续完成模板特化的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>

// 主模板
template<typename T>
class MyClass {
public:
static void print() {
std::cout << "General template" << std::endl;
}
};

// 特化版本(int)
template<>
class MyClass<int> {
public:
static void print() {
std::cout << "Specialized for int" << std::endl;
}
};

// 特化版本(double)
template<>
class MyClass<double> {
public:
static void print() {
std::cout << "Specialized for double" << std::endl;
}
};

// 特化版本(const char*)
template<>
class MyClass<const char*> {
public:
static void print() {
std::cout << "Specialized for const char*" << std::endl;
}
};

int main() {
MyClass<float>::print(); // 使用主模板
MyClass<int>::print(); // 使用int特化版本
MyClass<double>::print(); // 使用double特化版本
MyClass<const char*>::print(); // 使用const char*特化版本

return 0;
}

模板元编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>

// 计算阶乘的元函数
template<int N>
struct Factorial {
static constexpr int value = N * Factorial<N - 1>::value;
};

// 特化版本(终止条件)
template<>
struct Factorial<0> {
static constexpr int value = 1;
};

// 计算斐波那契数列的元函数
template<int N>
struct Fibonacci {
static constexpr int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
};

// 特化版本(终止条件)
template<>
struct Fibonacci<0> {
static constexpr int value = 0;
};

template<>
struct Fibonacci<1> {
static constexpr int value = 1;
};

// 类型 traits
template<typename T>
struct is_integral {
static constexpr bool value = false;
};

template<>
struct is_integral<int> {
static constexpr bool value = true;
};

template<>
struct is_integral<long> {
static constexpr bool value = true;
};

template<>
struct is_integral<short> {
static constexpr bool value = true;
};

template<>
struct is_integral<char> {
static constexpr bool value = true;
};

// 条件模板
template<bool B, typename T, typename U>
struct conditional {
using type = T;
};

template<typename T, typename U>
struct conditional<false, T, U> {
using type = U;
};

int main() {
// 阶乘
std::cout << "Factorial<5>::value: " << Factorial<5>::value << std::endl;

// 斐波那契
std::cout << "Fibonacci<10>::value: " << Fibonacci<10>::value << std::endl;

// 类型 traits
std::cout << "is_integral<int>::value: " << is_integral<int>::value << std::endl;
std::cout << "is_integral<double>::value: " << is_integral<double>::value << std::endl;

// 条件模板
using Type1 = conditional<true, int, double>::type;
using Type2 = conditional<false, int, double>::type;
std::cout << "Type1 is int: " << std::is_same_v<Type1, int> << std::endl;
std::cout << "Type2 is double: " << std::is_same_v<Type2, double> << std::endl;

return 0;
}

可变参数模板(C++11+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

// 递归终止条件
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}

// 可变参数模板
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...); // 递归调用
}

// 计算参数个数
template<typename... Args>
size_t countArgs(Args... args) {
return sizeof...(args);
}

// 折叠表达式(C++17+)
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // 折叠表达式,等同于 (((arg1 + arg2) + arg3) + ...)
}

int main() {
// 打印多个参数
print(1, 2.5, "hello", true);

// 计算参数个数
std::cout << "countArgs(1, 2, 3): " << countArgs(1, 2, 3) << std::endl;
std::cout << "countArgs('a', 'b'): " << countArgs('a', 'b') << std::endl;

// 求和
std::cout << "sum(1, 2, 3, 4, 5): " << sum(1, 2, 3, 4, 5) << std::endl;
std::cout << "sum(1.5, 2.5, 3.5): " << sum(1.5, 2.5, 3.5) << std::endl;

return 0;
}

并发编程(C++11+)

线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <thread>
#include <vector>

void func(int id) {
std::cout << "Thread " << id << " started" << std::endl;
// 模拟工作
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Thread " << id << " finished" << std::endl;
}

int main() {
std::cout << "Main thread started" << std::endl;

// 创建线程
std::thread t1(func, 1);
std::thread t2(func, 2);

// 等待线程完成
t1.join();
t2.join();

// 创建多个线程
std::vector<std::thread> threads;
for (int i = 3; i < 6; ++i) {
threads.emplace_back(func, i);
}

// 等待所有线程完成
for (auto& t : threads) {
t.join();
}

std::cout << "Main thread finished" << std::endl;

return 0;
}

互斥量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

std::mutex mtx; // 互斥量
int sharedData = 0; // 共享数据

void increment(int id) {
for (int i = 0; i < 1000; ++i) {
// 加锁
std::lock_guard<std::mutex> lock(mtx); // RAII风格,自动解锁
// 临界区
sharedData++;
// 自动解锁
}
}

int main() {
std::vector<std::thread> threads;

// 创建10个线程
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, i);
}

// 等待所有线程完成
for (auto& t : threads) {
t.join();
}

std::cout << "Final sharedData: " << sharedData << std::endl; // 应该输出10000

return 0;
}

条件变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;
int data = 0;

void producer() {
// 模拟生产数据
std::this_thread::sleep_for(std::chrono::milliseconds(500));

{
std::lock_guard<std::mutex> lock(mtx);
data = 42;
ready = true;
std::cout << "Producer: Data produced: " << data << std::endl;
}

// 通知消费者
cv.notify_one();
}

void consumer() {
std::cout << "Consumer: Waiting for data..." << std::endl;

{
std::unique_lock<std::mutex> lock(mtx);
// 等待条件满足
cv.wait(lock, []{ return ready; });

// 条件满足,处理数据
std::cout << "Consumer: Data received: " << data << std::endl;
ready = false;
}
}

int main() {
std::thread t1(producer);
std::thread t2(consumer);

t1.join();
t2.join();

return 0;
}

原子操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>

std::atomic<int> sharedData(0); // 原子变量

void increment(int id) {
for (int i = 0; i < 1000; ++i) {
sharedData++;
// 或使用fetch_add
// sharedData.fetch_add(1);
}
}

int main() {
std::vector<std::thread> threads;

// 创建10个线程
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, i);
}

// 等待所有线程完成
for (auto& t : threads) {
t.join();
}

std::cout << "Final sharedData: " << sharedData << std::endl; // 应该输出10000

return 0;
}

其他特殊工具

类型别名(typedef和using)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>

// 使用typedef
typedef int Integer;
typedef std::vector<int> IntVector;

// 使用using(C++11+)
using Float = float;
using FloatVector = std::vector<float>;

// 模板别名(C++11+)
template<typename T>
using Vector = std::vector<T>;

int main() {
// 使用typedef
Integer i = 42;
IntVector iv = {1, 2, 3, 4, 5};

// 使用using
Float f = 3.14;
FloatVector fv = {1.1, 2.2, 3.3};

// 使用模板别名
Vector<int> v1 = {1, 2, 3};
Vector<double> v2 = {1.1, 2.2, 3.3};

std::cout << "i: " << i << std::endl;
std::cout << "f: " << f << std::endl;

return 0;
}

枚举类(C++11+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

// 传统枚举
enum Color {
RED, GREEN, BLUE
};

// 枚举类(强类型枚举)
enum class Direction {
UP, DOWN, LEFT, RIGHT
};

// 带底层类型的枚举类
enum class Status : int {
OK = 0,
ERROR = 1,
WARNING = 2
};

int main() {
// 传统枚举
Color color = RED;
std::cout << "Color::RED: " << color << std::endl;

// 枚举类
Direction dir = Direction::UP;
// std::cout << "Direction::UP: " << dir << std::endl; // 错误:枚举类不能直接输出

// 转换为底层类型
std::cout << "static_cast<int>(Direction::UP): " << static_cast<int>(Direction::UP) << std::endl;
std::cout << "static_cast<int>(Status::OK): " << static_cast<int>(Status::OK) << std::endl;

return 0;
}

内联命名空间(C++11+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

// 内联命名空间
inline namespace V1 {
void foo() {
std::cout << "V1::foo()" << std::endl;
}
}

// 非内联命名空间
namespace V2 {
void foo() {
std::cout << "V2::foo()" << std::endl;
}
}

int main() {
// 内联命名空间的成员可以直接访问
foo(); // 调用V1::foo()

// 非内联命名空间的成员需要显式访问
V2::foo(); // 调用V2::foo()

// 也可以显式访问内联命名空间的成员
V1::foo(); // 调用V1::foo()

return 0;
}

结构化绑定(C++17+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <tuple>
#include <vector>
#include <map>

int main() {
// 元组
std::tuple<int, double, std::string> t(1, 2.5, "hello");
auto [a, b, c] = t;
std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;

// 数组
int arr[] = {1, 2, 3};
auto [x, y, z] = arr;
std::cout << "x: " << x << ", y: " << y << ", z: " << z << std::endl;

// 结构体
struct Point {
int x;
double y;
};

Point p = {10, 20.5};
auto [px, py] = p;
std::cout << "px: " << px << ", py: " << py << std::endl;

// 映射
std::map<std::string, int> m = {{"one", 1}, {"two", 2}};
for (const auto& [key, value] : m) {
std::cout << key << ": " << value << std::endl;
}

return 0;
}

最佳实践

1. 类型转换

  • 优先使用static_cast:对于相关类型之间的转换
  • 使用dynamic_cast:对于多态类型之间的转换,需要运行时检查
  • 谨慎使用const_cast:只在必要时使用,避免修改const变量
  • 避免使用reinterpret_cast:这是最危险的转换,尽量避免使用

2. 异常处理

  • 合理使用异常:只对真正的异常情况使用异常
  • 捕获适当的异常:从具体到一般捕获异常
  • 使用noexcept:对于不会抛出异常的函数,使用noexcept说明
  • 异常安全:确保代码在抛出异常时保持一致的状态
  • 资源管理:使用RAII管理资源,避免资源泄漏

3. 内存管理

  • 使用智能指针:优先使用std::unique_ptr和std::shared_ptr
  • 使用std::make_unique和std::make_shared:避免裸指针
  • 避免循环引用:使用std::weak_ptr打破循环引用
  • 内存池:对于频繁分配和释放的小对象,考虑使用内存池

4. 元编程

  • 模板特化:用于为特定类型提供定制实现
  • SFINAE:用于基于类型特性选择不同的重载
  • 折叠表达式:C++17+中用于简化可变参数模板的实现
  • 类型 traits:用于在编译时获取类型信息

5. 并发编程

  • 使用标准库:优先使用std::thread、std::mutex等标准库组件
  • 避免共享状态:尽量减少线程间的共享状态
  • 使用原子操作:对于简单的共享变量,使用std::atomic
  • RAII风格的锁:使用std::lock_guard和std::unique_lock
  • 避免死锁:使用std::scoped_lock或std::lock避免死锁

常见错误和陷阱

1. 类型转换错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 错误:使用reinterpret_cast进行不相关类型转换
int x = 42;
std::string* strPtr = reinterpret_cast<std::string*>(&x); // 危险:未定义行为

// 错误:向下转换时不检查类型
Base* basePtr = new Base();
Derived* derivedPtr = static_cast<Derived*>(basePtr); // 危险:basePtr不是Derived类型

derivedPtr->foo(); // 未定义行为

// 正确:使用dynamic_cast并检查
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
derivedPtr->foo();
}

2. 异常处理错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 错误:捕获所有异常但不处理
try {
// 可能抛出异常的代码
} catch (...) {
// 不处理异常
}

// 错误:在析构函数中抛出异常
class MyClass {
public:
~MyClass() {
throw std::runtime_error("Error in destructor"); // 危险:可能导致std::terminate
}
};

// 正确:析构函数不应该抛出异常
class MyClass {
public:
~MyClass() noexcept {
try {
// 可能抛出异常的操作
} catch (...) {
// 处理异常,不重新抛出
}
}
};

3. 内存管理错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 错误:使用裸指针管理内存
MyClass* ptr = new MyClass();
// 忘记delete

// 正确:使用智能指针
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();

// 错误:循环引用
class A {
public:
std::shared_ptr<B> b;
};

class B {
public:
std::shared_ptr<A> a;
};

std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->b = b;
b->a = a;
// 循环引用,导致内存泄漏

// 正确:使用weak_ptr打破循环引用
class A {
public:
std::shared_ptr<B> b;
};

class B {
public:
std::weak_ptr<A> a; // 使用weak_ptr
};

4. 元编程错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 错误:模板特化顺序
// 一般模板
template<typename T>
class MyClass {
};

// 错误:在使用后定义特化模板
template<>
class MyClass<int> {
};

// 正确:先定义特化模板,再使用

// 错误:可变参数模板递归终止条件
// 缺少递归终止条件
template<typename... Args>
void print(Args... args) {
print(args...); // 无限递归
}

// 正确:提供递归终止条件
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}

template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...);
}

5. 并发编程错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 错误:死锁
std::mutex mtx1, mtx2;

void thread1() {
std::lock_guard<std::mutex> lock1(mtx1);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lock2(mtx2); // 可能导致死锁
}

void thread2() {
std::lock_guard<std::mutex> lock2(mtx2);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lock1(mtx1); // 可能导致死锁
}

// 正确:使用std::scoped_lock
void thread1() {
std::scoped_lock lock(mtx1, mtx2); // 原子方式锁定多个互斥量
}

void thread2() {
std::scoped_lock lock(mtx2, mtx1); // 顺序无关
}

// 错误:条件变量使用错误
std::condition_variable cv;
std::mutex mtx;
bool ready = false;

void consumer() {
cv.wait(std::unique_lock<std::mutex>(mtx)); // 错误:没有检查条件
// 可能虚假唤醒
}

// 正确:使用谓词
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 检查条件
}

小结

本章介绍了C++中的特殊工具和技术,包括:

  1. 类型转换运算符:static_cast、dynamic_cast、const_cast、reinterpret_cast
  2. 运行时类型识别(RTTI):typeid运算符
  3. 异常处理:try-catch语句、自定义异常、noexcept说明符
  4. 内存管理:智能指针、内存池
  5. 元编程:模板特化、模板元编程、可变参数模板
  6. 并发编程:线程、互斥量、条件变量、原子操作
  7. 其他特殊工具:类型别名、枚举类、内联命名空间、结构化绑定
  8. 最佳实践:类型转换、异常处理、内存管理、元编程、并发编程
  9. 常见错误和陷阱:类型转换错误、异常处理错误、内存管理错误、元编程错误、并发编程错误

这些特殊工具和技术是C++语言的高级特性,它们为程序员提供了更灵活、更强大的编程能力。然而,这些特性也需要谨慎使用,否则可能会导致代码质量下降、性能问题、甚至程序崩溃。在实际编程中,应根据具体情况合理使用这些特性,遵循最佳实践,避免常见错误。

通过本章的学习,读者应该对C++的高级特性有了全面的了解,能够在实际编程中灵活运用这些特性,编写高效、优雅、安全的C++代码。