C++编程技巧分享

一、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
map mp;    // 定义一个空的map
mp["hello"] = 1;        // 向map中插入一个键值对
mp.insert(pair("world", 2));
mp.erase("hello");      // 删除map中键为hello的元素

三、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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-17 16:06
下一篇 2024-12-17 16:06

相关推荐

发表回复

登录后才能评论