C++11特性汇总(1/...)简洁版(使用新特性实现线程池)

  • 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相关的新特性,我们就完成了一个基本的线程池的实现和使用示例。这个线程池可以动态地管理任务并利用多线程并行执行,以提高程序的性能和响应速度。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值