Home > Enterprise >  Deleting <template> objects, error: type ‘class Circular_Buffer<unsigned int>’ argument
Deleting <template> objects, error: type ‘class Circular_Buffer<unsigned int>’ argument

Time:01-18

I'm trying to optimize this code for a Microchip Fubarino.
the original code: https://gist.github.com/edwintcloud/d547a4f9ccaf7245b06f0e8782acefaa

delete cb; // error: type ‘class Circular_Buffer<unsigned int>’ argument given to ‘delete’, expected pointer

I tried many things, but nothing helped.

also

        printf("deleting buffer\n");
        for(uint32_t i = 0; i < max_size; i  )
            {
                //printf("deleting item %hhd\n", i);
                //printf("deleting item\n");
                delete (T*)buffer[i];//delete the A object allocations. // <-----
            } 

returns a warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

witch i though to have found a solution here, although it enabled me to compile: Error while deleting a vector pointer to pointers

#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H





// https://gist.github.com/edwintcloud/d547a4f9ccaf7245b06f0e8782acefaa

//===================================================================
// File: circular_buffer.cpp
//
// Desc: A Circular Buffer implementation in C  .
//
// Copyright © 2019 Edwin Cloud. All rights reserved.
//
//===================================================================

//-------------------------------------------------------------------
// Includes
//-------------------------------------------------------------------

#include <QCoreApplication>  // needed to use uint32_t

template <class T> class Circular_Buffer {
private:
    //---------------------------------------------------------------
    // Circular_Buffer - Private Member Variables
    //---------------------------------------------------------------

    T* buffer; // using a smart pointer is safer (and we don't
    // have to implement a destructor)
    //size_t head = 0;             // size_t is an unsigned long
    //size_t tail = 0;
    //size_t max_size;
    uint32_t head = 0;             // size_t is an unsigned long
    uint32_t tail = 0;
    uint32_t max_size;
    T empty_item;// = 0x00; // we will use this to clear data
public:
    //---------------------------------------------------------------
    // Circular_Buffer - Public Methods
    //---------------------------------------------------------------

    // Create a new Circular_Buffer.
    //Circular_Buffer<T>(char max_size)
    //    : buffer(unique_ptr<T[]>(new T[max_size])), max_size(max_size){};
    Circular_Buffer<T>(char max_size)
        : buffer(new T[max_size]), max_size(max_size){};
    //  buffer(std::make_unique<T[]>(max_size))
    //  std::unique_ptr<T[]>(new T[max_size]) // orginal

    ~Circular_Buffer<T>(){
        // https://stackoverflow.com/questions/2814188/c-array-of-pointers-delete-or-delete
        printf("deleting buffer\n");
        for(uint32_t i = 0; i < max_size; i  )
            {
                printf("deleting item %hhd\n", i);
                //printf("deleting item\n");
                //delete buffer[i];//delete the A object allocations.
            }
        buffer = NULL;
        delete[] buffer;
        this->head = 0;
        this->tail = 0;
        printf("detroyed\n");
    }

    // Add an item to this circular buffer.
    void enqueue(T item) {
        if(this->buffer == NULL){
            printf("Nothing to add\n");
            return;
        }
        // if buffer is full, throw an error
        //if (is_full()){
        //throw std::runtime_error("buffer is full");
        //}

        // insert item at back of buffer
        buffer[tail] = item;

        // increment tail
        tail = (tail   1) % max_size;
    }

    // Remove an item from this circular buffer and return it.
    T dequeue() {
        if(this->buffer == NULL){
            printf("Nothing to remove\n");
            return NULL;
        }
        // if buffer is empty, throw an error
        //if (is_empty()){
        //throw std::runtime_error("buffer is empty");
        //}

        // get item at head
        T item = buffer[head];

        // set item at head to be empty
        // T empty_item;  // redunant, declared above
        buffer[head] = empty_item;

        // move head foward
        head = (head   1) % max_size;

        // return item
        return item;
    }

    // Return the item at the front of this circular buffer.
    T front() { return buffer[head]; }

    // Return true if this circular buffer is empty, and false otherwise.
    bool is_empty() { return head == tail; }

    // Return true if this circular buffer is full, and false otherwise.
    bool is_full() { return tail == (head - 1) % max_size; }

    // Return the size of this circular buffer.
    char size() {
        if (tail >= head)
            return tail - head;
        return max_size - head - tail;
    }
};
#endif // CIRCULAR_BUFFER_H


    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
    
        Circular_Buffer<uint32_t> cb(10);
    
        printf("\n === CircularBuffer Test ===\n");
        printf("Size: %hhd\n", cb.size());
    
        uint32_t x = 1;
        printf("Enqueue 1, val: %d\n", x);
        cb.enqueue(x);
        printf("Size: %hhd\n", cb.size());
        x = 2;
        printf("Enqueue 1, val: %d\n", x);
        cb.enqueue(x);
        printf("Size: %hhd\n", cb.size());
        printf("Enqueue 1, val: %d\n", x);
        cb.enqueue(x);
        printf("Size: %hhd\n", cb.size());
        x = cb.dequeue();
        printf("Dequeue: %d\n", x);
        printf("Size: %hhd\n", cb.size());
        x = cb.dequeue();
        printf("Dequeue: %d\n", x);
        printf("Size: %hhd\n", cb.size());
        x = cb.dequeue();
        printf("Dequeue: %d\n", x);
        printf("Size: %hhd\n", cb.size());
        x = cb.dequeue();
        printf("Dequeue: %d\n", x);
        printf("Size: %hhd\n", cb.size());
        printf("Empty: %d\n", cb.is_empty());
    
        cb.~Circular_Buffer<uint32_t>();
        delete cb; // <------------------------------------------
    
        printf("start over\n");
        uint32_t y = 1;
        printf("Enqueue 1, val: %d\n", y);
        cb.enqueue(y);
        printf("Size: %hhd\n", cb.size());
        y = 2;
        printf("Enqueue 1, val: %d\n", y);
        cb.enqueue(x);
        printf("Size: %hhd\n", cb.size());
        y = 3;
        printf("Enqueue 1, val: %d\n", y);
        cb.enqueue(x);
        printf("Size: %hhd\n", cb.size());
    }

CodePudding user response:

There are four problems with the code you have provided:

  1. You are allocating a block of integers that you are trying to treat as an array of pointers.
  2. You are explicitly calling the destructor for your class.
  3. You are then calling delete which will then also call the destructor for your class.
  4. You are using the pointer after it has been deleted.

When you instantiate your class with the type uint32_t, you are instructing the code to create a pointer to a contiguous memory space that is expected to contain elements of type uint32_t. These are not pointers. And based on the sample code, you did not want them to be pointers because you are not trying to queue pointers. Because these are not pointers you do not loop through to delete them. Even if they were pointers, you would be freeing the memory that they pointed to, not the memory that contains the address. When deleting an object that was created with new [] you need to call delete[]. As Andy Coffin mentioned in a comment below, you should not set the buffer to NULL before deleting it.

Do not call a destructor directly. Unless you are doing things with placement new where you are 'placing' an item in a managed memory space where the default delete functionality would cause problems, you should never call a destructor directly. The delete method will call it for you.

Calling delete after erroneously calling the destructor will result in bad things. A double delete is not your friend. Furthermore, you do not call delete on a variable that is not a pointer. You did not dynamically allocate the Circular_Buffer object so delete is not appropriate.

Finally, if you HAD used a pointer to create your circular buffer object, you would be trying to access it after the deletion.

Another option you might consider is something like this:

template <class T, int S> class X {
    T buffer[S]; 
};

No allocations required.

  • Related