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循环释放
  }
}

 

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