C++ memory allocation function std::calloc()

Function: void* calloc(size_t num, size_t size); num is the number of elements, and size is the byte length of each element.
The header file malloc.h
allocates n continuous spaces of size size in the dynamic storage area of ​​the memory, and the function returns a pointer to the starting address of the allocation; if the allocation is unsuccessful, it returns NULL.

Used to obtain a piece of array space, the array element is initialized to 0.

Generally use free (pointer of starting address) to release the memory after use.
The difference with malloc: After
calloc dynamically allocates memory, it automatically initializes the memory space to zero, while malloc does not initialize, and the data inside is random garbage data.

calloc can be used to allocate dynamic arrays, such as:

#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() can also be used for memory allocation of class:

For example, allocate a dynamic array to store the function object std::function<> class

#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;
}

The implementation of thread pool in Apollo formally uses the above method to define a pointer pool to a dynamic array, specify the size of the array during initialization, and allocate memory. The dynamic array is used to dynamically save the task queue.

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

 

Guess you like

Origin blog.csdn.net/sunlin972913894/article/details/105927200