C++內存分配函數std::calloc()

函數:void*  calloc(size_t num,size_t size); num爲元素個數,size爲每個元素的字節長度。
頭文件 malloc.h
在內存的動態存儲區中分配n個長度爲size的連續空間,函數返回一個指向分配起始地址的指針;如果分配不成功,返回NULL。

用於在取得一塊數組空間,數組元素初始化爲0.

一般使用後要使用 free(起始地址的指針) 對內存進行釋放。
跟malloc的區別:
calloc在動態分配完內存後,自動初始化該內存空間爲零,而malloc不初始化,裏邊數據是隨機的垃圾數據。

calloc可用於分配動態數組,比如:

#include <memory>
#include <iostream>

int main()
{
    double* arrPtr;
    size_t num=5;
    arrPtr = (double*)calloc(num,sizeof(double));

    for(int i=0;i<5;++i)
        std::cout<<&arrPtr[i]<<" "<<arrPtr[i]<<std::endl;

    free(arrPtr);

    return 0;
}

std::calloc()也可以用於class類的內存分配:

比如分配一個動態數組,用於存放函數對象std::function<>類

#include <malloc.h>
#include <iostream>
#include <functional>

using namespace std;

int a = 100;
int b = 15;

int addFun()
{
    return a + b;
}

int subtrFunc()
{
    return a -b;
}

int multiFun()
{
    return a*b;
}

float deviFun()
{
    return (float)a/b;
}

int modFun()
{
    return a%b;
}

int main()
{
    std::function<int()>* taskQueue;
    size_t size=16;
    size_t num=5;
    taskQueue=(std::function<int()>*)calloc(num,sizeof(std::function<int()>));

    std::function<int()> callback1 = std::bind(addFun);
    std::cout<<"callback size:"<<sizeof(callback1)<<std::endl;
    taskQueue[0] = callback1;

    std::function<int()> callback2 = std::bind(subtrFunc);
    std::cout<<"callback size:"<<sizeof(callback2)<<std::endl;
    taskQueue[1] = callback2;

    std::function<int()> callback3 = std::bind(multiFun);
    std::cout<<"callback size:"<<sizeof(callback3)<<std::endl;
    taskQueue[2] = callback3;

    std::function<int()> callback4 = std::bind(deviFun);
    std::cout<<"callback size:"<<sizeof(callback4)<<std::endl;
    taskQueue[3] = callback4;

    std::function<int()> callback5 = std::bind(modFun);
    std::cout<<"callback size:"<<sizeof(callback5)<<std::endl;
    taskQueue[4] = callback5;

    for(int i = 0;i < num; ++i)
    {
        std::cout<<taskQueue[i]()<<std::endl;
    }

    free(taskQueue);
    return 0;
}

Apollo中線程池的實現中正式用了上述的方法定義了一個指向動態數組的指針pool,初始化的時候指定數組大小,並分配內存,該動態數組用於動態保存任務隊列。

template <typename T>
class BoundedQueue {
 public:
  using value_type = T;
  using size_type = uint64_t;

 public:
  BoundedQueue() {}
  BoundedQueue& operator=(const BoundedQueue& other) = delete;
  BoundedQueue(const BoundedQueue& other) = delete;
  ~BoundedQueue();
  bool Init(uint64_t size);
  bool Init(uint64_t size, WaitStrategy* strategy);
  bool Enqueue(const T& element);
  bool Enqueue(T&& element);
  bool WaitEnqueue(const T& element);
  bool WaitEnqueue(T&& element);
  bool Dequeue(T* element);
  bool WaitDequeue(T* element);
  uint64_t Size();
  bool Empty();
  void SetWaitStrategy(WaitStrategy* WaitStrategy);
  void BreakAllWait();
  uint64_t Head() { return head_.load(); }
  uint64_t Tail() { return tail_.load(); }
  uint64_t Commit() { return commit_.load(); }

 private:
  uint64_t GetIndex(uint64_t num);

  alignas(CACHELINE_SIZE) std::atomic<uint64_t> head_ = {0};
  alignas(CACHELINE_SIZE) std::atomic<uint64_t> tail_ = {1};
  alignas(CACHELINE_SIZE) std::atomic<uint64_t> commit_ = {1};
  // alignas(CACHELINE_SIZE) std::atomic<uint64_t> size_ = {0};
  uint64_t pool_size_ = 0;
  T* pool_ = nullptr; //指向數組的指針,數組容器裏面保存的是T*類型
  std::unique_ptr<WaitStrategy> wait_strategy_ = nullptr;
  volatile bool break_all_wait_ = false;
};

...

template <typename T>
bool BoundedQueue<T>::Init(uint64_t size, WaitStrategy* strategy) {
  // Head and tail each occupy a space
  pool_size_ = size + 2;
  pool_ = reinterpret_cast<T*>(std::calloc(pool_size_, sizeof(T)));
  if (pool_ == nullptr) {
    return false;
  }
  for (uint64_t i = 0; i < pool_size_; ++i) {
    new (&(pool_[i])) T();
  }
  wait_strategy_.reset(strategy);
  return true;
}

...
template <typename T>
BoundedQueue<T>::~BoundedQueue() {
  if (wait_strategy_) {
    BreakAllWait();
  }
  if (pool_) {
    for (uint64_t i = 0; i < pool_size_; ++i) {
      pool_[i].~T();
    }
    std::free(pool_); //釋放的時候不需要for循環釋放
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章