C++ N-last added items container - c++

I try to find optimal data structure for next simple task: class which keeps N last added item values in built-in container. If object obtain N+1 item it should be added at the end of the container and first item should be removed from it. It like a simple queue, but class should have a method GetAverage, and other methods which must have access to every item. Unfortunately, std::queue doesn't have methods begin and end for this purpose.
It's a part of simple class interface:
class StatItem final
{
static int ITEMS_LIMIT;
public:
StatItem() = default;
~StatItem() = default;
void Reset();
void Insert(int val);
int GetAverage() const;
private:
std::queue<int> _items;
};
And part of desired implementation:
void StatItem::Reset()
{
std::queue<int> empty;
std::swap(_items, empty);
}
void StatItem::Insert(int val)
{
_items.push(val);
if (_items.size() == ITEMS_LIMIT)
{
_items.pop();
}
}
int StatItem::GetAverage() const
{
const size_t itemCount{ _items.size() };
if (itemCount == 0) {
return 0;
}
const int sum = std::accumulate(_items.begin(), _items.end(), 0); // Error. std::queue doesn't have this methods
return sum / itemCount;
}
Any ideas?
I'm not sure about std::deque. Does it work effective and should I use it for this task or something different?
P.S.: ITEMS_LIMIT in my case about 100-500 items

The data structure you're looking for is a circular buffer. There is an implementation in the Boost library, however in this situation since it doesn't seem you need to remove items you can easily implement one using a std::vector or std::array.
You will need to keep track of the number of elements in the vector so far so that you can average correctly until you reach the element limit, and also the current insertion index which should just wrap when you reach that limit.
Using an array or vector will allow you to benefit from having a fixed element limit, as the elements will be stored in a single block of memory (good for fast memory access), and with both data structures you can make space for all elements you need on construction.
If you choose to use a std::vector, make sure to use the 'fill' constructor (http://www.cplusplus.com/reference/vector/vector/vector/), which will allow you to create the right number of elements from the beginning and avoid any extra allocations.

Related

Own vector class for arduino (c++)

I added also void Clear()-method.
https://redstoner.com/forums/threads/840-minimal-class-to-replace-std-vector-in-c-for-arduino
https://forum.arduino.cc/index.php?topic=45626.0
I'm asking about this Vector class.
void push_back(Data const &x) {
if (d_capacity == d_size) resize();
d_data[d_size++] = x;
}; // Adds new value. If needed, allocates more space
How to add "insert"-method to this Vector class (arduino use C++ but not have a standard vector methods)?
Vector<Sensor*> sensors;
I have a another class Sensor and I use vector like this.
push.back(new Sensor (1,1,"Sensor_1",2));
Is it possible to add values one by one to this vector class? And how to do it?
I like to ask also other question.
How can I call delete/call destructor for this Vector "sensors" so all pointers are deleted? Or sensors vector is deleted? I want to clear the data and then add data to it.
If you want to add an item to the end of the vector, use the push_back method you've quoted above. If you want to add an item somewhere else in the vector, you'll need to add your own method which re-sizes if necessary, shifts the elements above the insert location up one place and then copies the new element into the correct slot. Something like this (untested):
void insert_at(size_t idx, Data const &data) {
assert(idx < d_size);
if (d_capacity == d_size) {
resize();
}
for (size_t i = d_size; i > idx; --i) {
d_data[i] = std::move(d_data[i - 1]);
}
d_data[idx] = data;
++d_size;
}
As Nacho points out, you might be better off with a linked list if you're going to do a lot of these insert operations, especially if the data you're storing is large and/or has a complex move operator.

Multi-index on boost::ptr_vector

I have the following classes in a program.
class Class1 {
public:
boost::ptr_vector<Class2> fields;
}
class Class2 {
public:
std:string name;
unsigned int value;
}
I want to write a member function in Class1 that returns a reference or pointer to an element in fields based on Class2's name variable. I don't have to be concerned with the lifetime of the objects in the container.
Currently, I am returning an iterator to the element I want after the function searches from the start of the vector to the element.
boost::ptr_vector<Class2>::iterator getFieldByName(std::string name) {
boost::ptr_vector<Class2>::iterator field = fields.begin();
while (field != fields.end()) {
if (field->name.compare(name) == 0) {
return field;
}
++field;
}
return fields.end();
}
The problems that I'm facing are:
(1.) I need to have fast random access to the elements or the program sits in getFieldByName() too long (a boost::ptr_vector<> is too slow when starting at the beginning of the container)
(2.) I need to preserve the order of insertion of the fields (so I can't use a boost::ptr_map<> directly)
I have discovered Boost::MultiIndex and it seems like it could provide a solution to the problems, but I need to use a smart container so that destruction of the container will also destruct the objects owned by the container.
Is there anyway to achieve a smart container that has multiple methods of access?
You can use two containers. Have a boost::ptr_map<> that stores the actual data, and then have a std::vector<> that stores pointers to the nodes of the map.
boost::ptr_map<std::string, Class2> by_field;
std::vector<Class2 const*> by_order;
void insert(Class2* obj) {
if (by_field.insert(obj->name, obj).second) {
// on insertion success, also add to by_order
by_order.push_back(obj);
}
}
This will give you O(lg n) access in your getFieldByName() function (just look it up in by_field) while also preserving the order of insertion (just look it up in by_order).

Can't Save structure content

I have the next problem:
I created the structure:
struct Series : vector<Candle>
{
Security Sec;
int LookFor;
int TF;
int Corrector;
string ID;
int line;
Series(){};
Series (int _lookfor);
void Update();
};
Constructor:
Series::Series (int _lookfor)
{
LookFor=_lookfor;
for (int i = 1; i<=LookFor; i++)
{
Candle cantype = Candle(i);
push_back(cantype);
}
}
So, then we call this construcor it fills object by candle-values. LookFor - is a number of candles in the vector-series.
After initialization i want update this serie (if there is more new candle, i want delete last one and insert new on the begining of vector-serie)
void Series::Update()
{
if (size()==LookFor)
{
if (newer(cantype,c1))
{
Candle cantype = Candle(1);
Candle c1 = at(0);
pop_back();
emplace(begin(),cantype);
}
}
I need to initialize a vector of these series:
vector vec;
vec.push_back(Series(3));
And constructor does its job, everithing is fine.
But then i update them:
for (size_t x =0; x<=size()-1;x++) vec[x].Update();
I have a problem: it cann't save changes in vector. In Update method everithing is fine, it inserts needed candle in itself, but then method is ended - the state of vector (each element of vec) has no changes. In method we see changes, but after it vector become after constructor-like, the state still the same.
Tell me, please, what am I doing wrong?
As others already mentioned, do not derive from these containers (could cause nasty errors like missing dtor calls and memory leaks, no virtual destructor is present in these containers). Instead, add the vector as a member or leave it as is, if you do private inheritance.
You may use the iterator interface for such containers:
for(std::vector<Series>::iterator sIt = vec.begin();sIt != vec.end();++sIt) sIt->Update();
For your task, consider using a deque or a list as a circular buffer instead of the vector for the Candles. It would perform better for insertions and therefore allows you to use push_front() instead of emplace() or insert().
Alternatively, you could hold an index of the vector element just past the last element (which should be the first) and just assign the new candle, et voilĂ , you've got a dense circular buffer.
There are implementations of such circular buffers, for example the one of boost:
http://www.boost.org/doc/libs/1_52_0/libs/circular_buffer/doc/circular_buffer.html
Despite logic issues, which could prevent the modification in certain states, I can't see, why your code doesn't work at all, at least not when I went through the snippets you posted.

std::sort is slow with small amounts of data

I'm finding that std::sort is very slow with sorting only 1000 items.
In class template template <typename T> class TableModel : public QAbstractTableModel I have the following function to sort a table.
template<typename T>
void TableModel<T>::sort(int column, Qt::SortOrder order = Qt::AscendingOrder) {
if(order == Qt::AscendingOrder) {
qSort(m_list.begin(), m_list.end(), less<T>(column));
} else {
qSort(m_list.begin(), m_list.end(), greater<T>(column));
}
reset();
}
I notice if I only have the randomly shuffle my table is shuffles then displays instantly. So this leads me to think that its sort that is slow. Can anyone help me speed up the sorting of a QTable?
Here is the less struct.
template<typename T>
struct less {
int index;
less(int index) : index(index) {}
bool operator()(const T& first, const T& second) {
return T::less(first, second, index);
}
};
T::less is a function and all it does it the less than comparison based on the index given.
Slow is defined as a 5 seconds for only 1000 items when I need to handle about 100,000 items later on.
I suspect that m_list is storing the items by value and that swapping them is expensive. You could try to either implement a faster swap or store them in the container by smart pointer.
Of course a profiler could help you pinpoint the problem much more precisely.
Since m_list is a QList it does not have the same interface or performance characteristics as a normal list. For example, apparently a QList stores an array of T* internally. This representation could be sorted without any copying if the sort algorithm is aware of this implementation detail. By contrast std::sort is probably deep copying the values around, or maybe moving them, which is going to be more work than sorting pointers in the QList array.
It's probably best to use Qt containers with Qt algorithms, since Qt algorithms are more likely to be specialized for Qt containers. Or you could avoid using Qt containers and just stick with the standard library.
Anyway, try using Qt's qSort algorithm:
template<typename T>
void TableModel<T>::sort(int column, Qt::SortOrder order = Qt::AscendingOrder) {
if(order == Qt::AscendingOrder) {
qSort(m_list.begin(), m_list.end(), less<T>(column));
} else {
qSort(m_list.begin(), m_list.end(), greater<T>(column));
}
reset();
}
Original answer
std::sort can't take advantage of the fact that nodes in the list can be moved around without copying the element. Assuming you're using std::list or something similar, use the sort member function.
template<typename T>
void TableModel<T>::sort(int column, Qt::SortOrder order = Qt::AscendingOrder) {
std::random_shuffle(m_list.begin(), m_list.end());
if(order == Qt::AscendingOrder) {
m_list.sort(less<T>(column));
} else {
m_list.sort(greater<T>(column));
}
reset();
}
If you can't do that then you may be able to optimize all those copies by making sure that your elements are move-enabled if you're using C++11.

boost::circular_buffer increment begin pointer without use push_back()

I just want to increment pointer of boost::circular_buffer container without use of push_back() method. I saw an increment() method but it is in private section. I need write directly to circular buffer, because it is faster than I prepare the data and insert to buffer using push_back().
This is what I have now. It is slow because two copies are involved every time I push_back():
struct big_data_block
{
char data[100000];
};
boost::circular_buffer<big_data_block> m_buffer(8);
void FillBuffer()
{
big_data_block block;
ReadFromAnywhere(&block);
buffer.push_back(block);
}
This is what I want, but function like IncrementBackPointer() does not exist.
void FillBuffer()
{
ReadFromAnywhere(buffer.end() - 1);
buffer.IncrementBackPointer();
}