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/zh-hant/n/275736.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-17 16:06
下一篇 2024-12-17 16:06

相關推薦

發表回復

登錄後才能評論