一、C++中的const
C++中的const限定符可以用于变量、函数参数、函数返回类型等多种情况。使用const限定符可以使代码更加安全、简洁、易于维护。
1、 const变量
const变量在定义后就不能被修改,这使得代码更加安全。对于只读变量,建议使用const限定符。
const int MAX_SIZE = 100; int main() { const int a = 10; a = 20; // error: assignment of read-only variable 'a' return 0; }
2、const函数参数
const函数参数可以避免函数内部无意义的变量修改,使得代码更加简洁和易于维护。
void foo(const int a) { a = 10; // error: assignment of read-only parameter 'a' }
3、const函数返回类型
const函数返回的变量不能被修改,使用const返回类型可以防止返回的数据在外部被意外修改。
const int& get_max(const int& a, const int& b) { return a > b ? a : b; }
二、C++中的STL容器
STL(Standard Template Libraries)是一个通用的C++标准库,其中包含了很多现成的数据结构和算法。STL容器是STL库中的一种数据结构,包括vector、list、set、map等。
1、vector
vector是一个动态的数组,可以存储任意类型的数据。vector提供了类似数组的随机访问能力,并能够动态地调整容量大小。
#include vector v; // 定义一个空的vector vector v(10); // 定义一个大小为10的vector,初始值都为0 v.push_back(1); // 在vector尾部插入一个元素1 v.pop_back(); // 从vector尾部删除一个元素 int size = v.size();// 获取vector中当前的元素个数
2、list
list是一个双向链表,可以存储任意类型的数据。list提供了类似数组的插入、删除、移动等操作,但没有随机访问能力。
#include list l; // 定义一个空的list l.push_back(1); // 在list尾部插入一个元素1 l.push_front(2); // 在list头部插入一个元素2 l.pop_back(); // 从list尾部删除一个元素 l.pop_front(); // 从list头部删除一个元素
3、set
set是一个集合,可以存储任意类型的数据。set以排序的方式存储数据,且每个元素仅出现一次。
#include set s; // 定义一个空的set s.insert(1); // 向set中插入元素1 s.insert(2); s.erase(2); // 删除set中元素2
4、map
map是一个关联数组,可以存储任意类型的数据。map以排序的方式存储数据,每个元素是一个键值对。
#include
三、C++中的多线程编程
C++11引入了多线程库,可以更简单地开发多线程应用。多线程编程可以提高程序的并发性能,但也会带来一些问题。
1、使用多线程进行并行计算
多线程编程中常用的并发计算方法是线程池。线程池是一种预先分配了多个线程的程序结构,这些线程统一管理,循环执行任务,可有效节约线程创建和销毁的开销。
#include #include #include #include using namespace std; class ThreadPool { public: ThreadPool(int n) :stop_flag_(false) { for (int i = 0; i < n; i++) { threads_.push_back(thread(&ThreadPool::Process, this)); } } ~ThreadPool() { Stop(); for (auto& t : threads_) { t.join(); } } void AddTask(function f) { { unique_lock lock(mutex_); tasks_.push(f); } cv_.notify_one(); } void Stop() { { unique_lock lock(mutex_); stop_flag_ = true; } cv_.notify_all(); } private: void Process() { while (true) { function f; { unique_lock lock(mutex_); cv_.wait(lock, [this](){ return !tasks_.empty() || stop_flag_; }); if (stop_flag_) break; f = tasks_.front(); tasks_.pop(); } f(); } } bool stop_flag_; queue<function> tasks_; vector threads_; mutex mutex_; condition_variable cv_; }; int main() { ThreadPool pool(4); for (int i = 0; i < 10; i++) { pool.AddTask([i](){ cout << "Task " << i << " is running." << endl; }); } pool.Stop(); return 0; }
2、多线程带来的问题
多线程编程会带来一些问题,例如竞态条件、死锁、饥饿等。其中最常见的竞态条件就是多个线程同时访问同一份数据,导致数据不一致的问题。
避免竞态条件的方法通常是在关键代码段加锁,使得同一时间只有一个线程能够执行这段代码。这样虽然能解决竞态条件问题,但也会带来一些开销,例如锁的创建、销毁、加锁、解锁等消耗都很大,同时也会降低并发性能。
3、C++11中的原子操作
原子操作是在不需要锁的情况下实现同步的一种方式,能够提高程序的并发性能。
例如,C++11中的atomic类型可以保证对T的操作都是原子的。
atomic cnt(0); void ThreadFunc() { for (int i = 0; i < 10000; i++) { cnt++; // 相当于cnt = cnt + 1,这里的操作是原子的 } } int main() { vector v; for (int i = 0; i < 4; i++) { v.push_back(thread(ThreadFunc)); } for (int i = 0; i < 4; i++) { v[i].join(); } cout << cnt << endl; // 正确输出:40000 return 0; }
C++11中还提供了一些其他的原子类型,例如std::atomic_flag、std::atomic_bool、std::atomic_int等。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/275736.html