0

I am trying to create a vector filled with class objects, and the class objects contain circular buffers as one of their members. I am running into this error:

In file included from .pio/libdeps/teensy40/Vector/src/Vector.h:95:0,
                 from src/main.cpp:2:
.pio/libdeps/teensy40/Vector/src/Vector/VectorDefinitions.h: In instantiation of 'void Vector<T>::push_back(const T&) [with T = Node]':
src/main.cpp:25:27:   required from here
.pio/libdeps/teensy40/Vector/src/Vector/VectorDefinitions.h:162:22: error: use of deleted function 'Node& Node::operator=(const Node&)'
     values_[size_++] = value;
                      ^
src/main.cpp:5:7: note: 'Node& Node::operator=(const Node&)' is implicitly deleted because the default definition would be ill-formed:
 class Node
       ^
src/main.cpp:5:7: error: use of deleted function 'CircularBuffer<T, S, IT>& CircularBuffer<T, S, IT>::operator=(const CircularBuffer<T, S, IT>&) [with T = long unsigned int; unsigned int S = 100u; IT = unsigned char]'
In file included from src/main.cpp:3:0:
.pio/libdeps/teensy40/CircularBuffer/CircularBuffer.h:64:18: note: declared here
  CircularBuffer& operator=(const CircularBuffer&) = delete;
                  ^
*** [.pio/build/teensy40/src/main.cpp.o] Error 1
======================================== [FAILED] Took 0.99 seconds ========================================

I created a program that is the minimum code I could to replicate the error:

#include <Arduino.h>
#include <Vector.h>
#include <CircularBuffer.h>

class Node
{
  CircularBuffer<uint32_t, 100> RTTSamplesBuffer;
};

// Vector to hold the nodes we currently have saved
Vector<Node> Nodes;
// This stuff is used in setup to make the vector not use dynamic allocation
// This version of the Vector library is special for arduino so it is not
// dynamically allocating the vector to prevent filling the controllers memory
const int NODE_COUNT_MAX = 20;
Node storage_array[NODE_COUNT_MAX];

void setup()
{
  Serial.begin(115200);
  // Point the vector to it's storage location.
  Nodes.setStorage(storage_array);

  while (!Serial)
    ;

  // Create Node I want to add to the vector
  Node testNode;

  // Try and add the Node to the vector.
  Nodes.push_back(testNode);

  while (1)
    ;
}

void loop()
{
  // put your main code here, to run repeatedly:
}

I am using this library for vectors as it is compatible with Arduino and won't fill up the memory, and I am using this library for the circular buffer. Thank you!

  • That circular buffer class does not like to move. at all. [link to github](https://github.com/rlogiacco/CircularBuffer/blob/cf4ded93a099eb77c9451ee56b3eeaf31c69b7a3/CircularBuffer.h#L58) That seems a little excessive for a container type... –  Jun 10 '21 at 20:12
  • And the Vector does not support `emplace()`... Using both these classes together is probably a bad idea... –  Jun 10 '21 at 20:13
  • I'm trying to have the class contain a buffer for data, as well as other values such as an address, time to leave, and such. Is there a better way to hold the data? I don't want to have to iterate over the array each time I add a new data point – Spencer Brennessel Jun 10 '21 at 20:15
  • 1
    @callyalater nah, storage is set: `Nodes.setStorage(storage_array);`. Also, that vector class is weird. The storage is actually a list of fully-constructed objects that are reassigned as needed instead of aligned_storage<> as you'd expect.. –  Jun 10 '21 at 20:22
  • @Frank I saw that afterwards, which is why I deleted my comment. Though in looking through the implementation, it appears that with the copy constructor implicitly deleted in `Node` and explicitly deleted for `CircularBuffer`, trying to do a `push_back` (without moving the object into the vector, rather than copying it) will cause an error. I'm not entirely sure though – callyalater Jun 10 '21 at 20:26
  • With no move construction/assignment available in `Vector` and only move construction/assignment available in `CircularBuffer`/`Node`, it seems that these are not compatible structures to use together without `std::move` or `std::forward` support. Just taking a cursory look at the code, that is what my best guess would be – callyalater Jun 10 '21 at 20:34
  • Is there a better library for a circular buffer I could use? Or should I use a vector for this buffer instead? – Spencer Brennessel Jun 10 '21 at 20:36

1 Answers1

1

Looking at the code of the circular buffer:

    CircularBuffer(const CircularBuffer&) = delete;
    CircularBuffer(CircularBuffer&&) = delete;
    CircularBuffer& operator=(const CircularBuffer&) = delete;
    CircularBuffer& operator=(CircularBuffer&&) = delete;

This means that the circular buffer, once allocated, cannot be moved or copied in any way. It stays where it is, and that will also apply to any type that has one of these as a member.

Adding a level of indirection so that the CircularBuffers are only ever reffered to, instead of being copied around, will get you out of that jam.

Roughly like this:

class Node
{
  using buffer_type = CircularBuffer<uint32_t, 100>;

  buffer_type* RTTSamplesBuffer = nullptr;

public:
  set_buffer(buffer_type* b) {
    RTTSamplesBuffer = b;
  }
};

const int NODE_COUNT_MAX = 20;
Node storage_array[NODE_COUNT_MAX];
Node::buffer_type buffers[NODE_COUNT_MAX];

void setup()
{
  for(int i=0; i<NODE_COUNT_MAX; ++i) {
    storage_array[i].set_buffer(&buffers[i]);
  }

  // ...
}

Normally this is where there "should" be a lot of hand-wringing about the rule of 0/3/5. However, as long as these are pointers to globally allocated objects, it's not strictly necessary.