-
auto
自动类型推导
auto x = 5; // x 的类型被推导为 int
auto pi = new auto(3.14); // pi 的类型被推导为 double*
使用场景: 简化复杂类型的声明,提高代码可读性。
优点: 减少冗余,使代码更易维护。
缺点: 可能导致可读性下降,特别是在复杂的推导情况下。
-
for-each
区间循环
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (auto& num : numbers) {
std::cout << num << " ";
}
使用场景: 遍历容器元素,简化迭代器操作。
优点: 语法简洁,减少传统
for
循环的繁琐。缺点: 无法直接访问索引,不适合需要索引的操作。
-
std::unique_ptr
/ std::shared_ptr
智能指针
// std::make_unique<>() 是C++ 14 引入的新函数
std::unique_ptr<int> ptr = std::make_unique<int>(42);
std::shared_ptr<int> sharedPtr = std::make_shared<int>(10);
// 检查对象是否为空
if(!ptr || ptr == nullptr)
// 重置对象
ptr.reset();
// 转移对象所有权
std::unique_ptr<int> ptr1(new int(55));
std::unique_ptr<int> ptr2 = std::move(ptr1);// ptr1将为空
-
Lambda
表达式
// Lambda 表达式来自定义排序规则
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 降序排序
});
// 算法函数中使用
std::vector<int> nums = {1, 2, 3, 4, 5};
std::for_each(nums.begin(), nums.end(), [](int x) {
std::cout << x * x << " ";
}); // 输出平方
auto it = std::find_if(nums.begin(), nums.end(), [](int x) {
return x % 2 == 0;
}); // 返回nums中第一个偶数
if (it != nums.end()) {
std::cout << "First even number found: " << *it << std::endl;
}
// 捕获外部变量
int x = 10;
int y = 20;
auto func1 = [x, y]() {
std::cout << "x: " << x << ", y: " << y << std::endl;
};
// 按引用捕获,可以直接修改外部的变量 x 和 y 的值,并且这些修改会影响到外部作用域中的 x 和 y
auto func2 = [&x, &y]() {
x++;
y++;
std::cout << "x: " << x << ", y: " << y << std::endl;
};
使用场景: 定义短小的匿名函数,作为算法的谓词或者回调函数。
优点: 简化函数对象的定义,使代码更为紧凑。
缺点: 可能使代码可读性下降,复杂的 lambda 表达式难以理解。
-
Move Semantics / R-value reference
右值引用/移动语义
右值引用支持移动语义,即通过 std::move 转移资源而非复制,提高效率
std::vector<std::vector<int>> vecOfVec;
for (int i = 0; i < 5; ++i) {
std::vector<int> &&tempVec = std::vector<int>(1000000, i);
vecOfVec.push_back(std::move(tempVec));
}
使用场景: 提高容器和其他资源的移动效率。
优点: 减少不必要的内存拷贝,提高性能。
缺点: 需要理解和正确使用移动语义,否则可能导致未定义行为。
-
std::thread / std::mutex
并发支持
#include <thread>
#include <mutex>
std::mutex mtx;
void threadFunction() {
std::lock_guard<std::mutex> lock(mtx);
task();
}
int main() {
std::thread t(threadFunction);
t.join();
return 0;
}
使用场景: 实现并发执行的多线程程序。
优点: 提高程序的响应性和性能。
缺点: 需要谨慎处理线程同步,避免死锁和数据竞争。
-
Perfect Forwarding
完美转发,允许函数模板将它们接收到的参数原样转发给其它函数,包括参数的值类别(左值或右值)和引用类型。
template <typename T>
void forwarder(T&& arg) {
processor(std::forward<T>(arg));
}
如果 forwarder 接收到一个左值,如 int x = 5; forwarder(x);,则 T 被推导为 int&,此时 std::forward<T>(arg) 将 arg 作为 int& 类型传递给 processor,确保传递的是左值引用。
如果 forwarder 接收到一个右值,如 forwarder(10);,则 T 被推导为 int,std::forward<T>(arg) 将 arg 作为 int&& 类型传递给 processor,确保传递的是右值引用,从而可以使用移动语义。
-
decltype
推导返回类型
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
/*
decltype(t + u):用于推断表达式 t + u 的类型。
auto add(T t, U u) -> decltype(t + u):使用尾置返回类型语法,函数 add 的返回类型将是 decltype(t + u) 推导出的类型。
*/
int a = 5;
double b = 6.7;
auto result1 = add(a, a); // decltype(a + a) => int, 返回类型为 int
auto result2 = add(a, b); // decltype(a + b) => double, 返回类型为 double
使用
decltype
可以推导表达式的类型,特别适用于模板函数的返回类型推断。
-
constexpr
允许函数在编译时求值,增加了编译时计算的能力,提高了效率。
constexpr int square(int x) {
return x * x;
}
-
override / final
class Base {
public:
virtual void foo() const;
};
class Derived : public Base {
public:
void foo() const override; // 明确表明覆盖基类的虚函数
};
class FinalClass final {
// 无法被继承的类
};
override
用于明确表明重写基类的虚函数,final
用于指示类不能被继承。
然后?可以利用上面提到的特性写一个线程池!
-
定义线程池类 ThreadPool,并声明需要的成员变量和方法
ThreadPool.h
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t numThreads); // 构造函数声明
// 添加任务到线程池的方法声明
template<class F, class... Args>
void enqueue(F&& f, Args&&... args);
~ThreadPool(); // 析构函数声明
private:
std::vector<std::thread> workers; // 工作线程
std::queue<std::function<void()>> tasks; // 任务队列
std::mutex queueMutex; // 任务队列互斥锁
std::condition_variable condition; // 条件变量
bool stop; // 停止标志
};
构造函数实现
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
// 创建工作线程,使用 lambda 表达式
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) {
return;
}
// 移动语义
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
实现任务添加方法
template<class F, class... Args>
void ThreadPool::enqueue(F&& f, Args&&... args) {
{
std::unique_lock<std::mutex> lock(queueMutex);
// 任务队列互斥锁
tasks.push(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
// 完美转发
}
condition.notify_one(); // 通知一个等待中的线程开始执行任务
}
析构函数
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all(); // 唤醒所有等待中的线程
// for-each
for (std::thread& worker : workers) {
worker.join(); // 等待所有线程结束
}
}
main中使用该线程池类
#include <iostream>
#include <vector>
#include <chrono>
#include "ThreadPool.h"
// 计算斐波那契数列的函数
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
const int numTasks = 10;
const int numThreads = 4;
// 创建线程池
ThreadPool pool(numThreads);
// 向线程池中添加多个任务
std::vector<std::future<int>> results;
for (int i = 0; i < numTasks; ++i) {
results.emplace_back(
pool.enqueue([](int n) {
return fibonacci(n);
}, i)
);
}
// 获取并打印每个任务的结果
for (int i = 0; i < numTasks; ++i) {
int result = results[i].get(); // 等待任务完成并获取结果
std::cout << "Fibonacci(" << i << ") = " << result << std::endl;
}
return 0;
}
这样,通过使用C++11相关的新特性,我们就完成了一个基本的线程池的实现和使用示例。这个线程池可以动态地管理任务并利用多线程并行执行,以提高程序的性能和响应速度。