optimization: vector.erase() of pointer - pointers

I have a question about deleting a dynamic vector of pointers and optimization.
Here is my code. It checks wether an element has to be set to nullptr and then it delete all those elements.
for (auto* el : elements)
{
if (el != 0)
// do something
else
el = nullptr;
}
elements.erase(std::remove(elements.begin(), elements.end(), nullptr), elements.end());
Is the complexity of this operation onerous for the machine ?
And if it is, then is there a better way of doing it and it is worth it ? Because, here, the preservation of the index order is not important for me.
Thank you !

Is the complexity of this operation onerous for the machine ?
It is a bit costly, but not much more than the previous operation. Indeed, remove will typically check the value of each item, and if an item needs to be removed, the algorithm shifts the item on the right to put it on the current analysed item. erase is often relatively cheap since it just resizes the vector to skip the remaining garbage at the end (generally without any copy or reallocation) and call the destructor of the discarded items (costly only if there is a lot of them and the destructor is non-trivial). This operation can be as costly as the previous one.
And if it is, then is there a better way of doing it and it is worth it ? Because, here, the preservation of the index order is not important for me.
Yes, this is possible: you can just iterate over the array with a classical loop and swap the current item with the one of the end to discard it. You need to maintain a end iterator moving from the end to the beginning. The loop stops when the end iterator is reached. Note that the swapped items coming from the end should be checked by your predicate too.
Alternatively, you could just use std::partition at this algorithm does a quite similar job and is simpler: it puts the items validating a given condition to the left part and put the other on the right part. You can then just resize the array to remove the unwanted right part.
std::partition should is bit less efficient than the other swap-based approach only if there is a lot of item to remove since it has to maintain the consistency of both sides.
Here is an (untested) example with std::partition:
auto discardedBegin = partition(elements.begin(), elements.end(), doSomething);
elements.erase(discardedBegin, elements.end());

Related

QList of Qvectors clear

In Qt documentation there is an example, where they use
foreach (QVector<QPointF> row, m_data)
row.clear();
m_data.clear();
to clear <QList<QVector<QPointF> > m_data;
Is it necessary to use such a construction or just m_data.clear(); is enoungh?
Qt example page.
Not only it is useless, but is can be "harmful".
It is useless because QList<T>::clear() will destroy every T it owns effectively calling ~T(). In your case that means that you end up calling ~QVector<QPointF>() for every vector in the QList. And then ~QVector<QPointF>() will call ~QPointF() for every point.
It can be harmful performance wise because QList and QVector use Copy-on-Write. That means that when you copy a list you do not copy the internal data, but a copy will happen as soon as you perform an action that will modify one of the list.
So if m_data shares its internal data with another QList, changing any of its element (eg. by calling QVector::clear() on one of them) will trigger a hard copy of the QList internal data. And this copy is completely useless as you discard it just after by calling m_data.clear().
Also worth noting that:
foreach (QVector<QPointF> row, m_data)
row.clear();
Does not change m_data. You clear row which is a local variable. And even if you en up writing:
foreach (QVector<QPointF> &row, m_data)
row.clear();
It will have no effect as, quoting Qt doc:
Since foreach creates a copy of the container, using a non-const
reference for the variable does not allow you to modify the original
container. It only affects the copy, which is probably not what you
want.

How to free resources of QString when use it inside std::vector

I have a structure "rs" for every record of my dataset.
All records are in a vector "r".
My record count is in “rc”.
....
struct rs{
uint ip_i;//index
QString ip_addr;//ip address
};
std::vector <rs> r;//rows ordered by key
int rc;//row count
....
I would like to control this memory usage.
That's why I don't want to use r.insert and r.erase.
When I need to insert a record, I will:
Increase size of r by r.resize(..);r.shrink_to_fit() (if needed).
Shift elements of r to the right (if needed) by std::rotate.
Put new values: r[i].ip_i=...;r[i].ip_addr=...
When I need to delete a record, I will:
Shift elements of r to the left (if needed) by std::rotate.
For example, std::rotate(r.begin()+i,r.begin()+i+1,r.begin()+rc);.
Free resources of r[rc].ip_addr.
How to free resouces of QString r[rc].ip_addr?
I've tried to do r[i].ip_addr.~QString() and catched an runtime error.
Make r.resize() (if needed).
I don't want to loose memory because of Qstring copies stayed after rows deleting.
How can I control them?
Thanks.
QString handles all memory control for you. Just treat it as a regular object and you'll be fine. std::vector is OO-aware, so it will call destructors when freeing elements.
The only thing you should not do is use low-level memory manipulation routines like memcpy or memset. std::vector operations are safe.
If you really want to free a string for a record that is within [0..size-1] range (that is, you do not actually decrease size with resize() after moving elements), then calling r[i].ip_addr.clear() would suffice. Or better yet, introduce the clear() method in your structure that will call ip_addr.clear() (in case you add more fields that need to be cleared). But you can only call it on a valid record, of course, not one beyond your actual vector size (no matter what the underlying capacity is, it's just an implementation detail).
On a side note, it probably makes sense to use QList instead since you're using Qt anyway, unless you have specific reasons to use std::vector. As far as memory control goes, QList offers reserve method which allows you reserve exactly as many elements as you need. Inserting then would look like
list.reserve(list.size() + 1);
list.insert(i, r);

Programming: Detect the direction and stop of change of a number

Any language, just pseudocode.
I'm searching around for an algorithm that detects direction and the stop of changes to a number. E.g.:
function detectChange(int number) {
if number is rising return "rising"
if number is dropping return "dropping"
if number is unchanged return "unchanged"
}
main() {
int number
while(true) {
//The read doesn't always happen
if readObscure.readoccured() {
//read the number from an obscure source
number = readObscure()
print(detectChange(number))
}
}
}
I've been working on an approach with a time delta but with little success. One problem is e.g. that with the timing approach I always miss the last change. Maybe I could solve that too but it's already pretty hacky.
So I'd be glad about a clean "textbook" solution, preferably without using time but just logic. If there's none without time, but still a clean solution, I'd appreciate that too.
Solution can be written in any "human readable" language (no haskell please) or pseudocode, I don't care.
I should have mentioned that the readObscure() function may also return the same number over and over again, or won't return a number at all, in which case I want to assume that the number is "unchanged".
Let's also update this with some examples:
readObscure() returns the numbers 1,2,14,15,8,17,20
This should be "rising"
readObscure() returns the numbers 1,2,14,15,17,20,20,20
This should be "rising" and then "unchanged"
So the question also is, how to define rising, unchanged, dropping. I'd like someone who maybe worked on those problems before to define it. The result should equal a "human sorting", so I look at the numbers and can immediatly tell, they are not rising, or they are rising.
I've been made aware of Rx (Reactive Extensions)
But for my personal case this is using a sledge-hammer to crack a nut.
Just make it so that whenever you add a value:
Take the value of the current and the last value, compute its delta.
Then, add it to wherever you're holding the deltas.
If you want something to "fire" everytime you "add a value," it's probably best to bind it to the container or some sort of callback/event-based mechanism/structure to ensure this. Boost.Signals2 (C++) is supposed to be a good way to handle this, but something as simple as creating an asynchronous thread of execution to compute and then push your value to the back of the storage vector would be good enough.

What happens to QVector's item when it's deleted elsewhere?

I'm wondering about what happens when I delete a QVector's item?
Is it automatically removed from the
QVector?
Do I have to remove it manually?
Also, how can I find out the index of an iteration of the iterator?
Best regards
If you have a QVector<Thing*> and delete one of the Things that stored in it, it will not be removed automatically from the vector. You need to do that yourself.
As far as I know, and from what I read in the docs, none of the QVector iterators has a method to tell at what index it is positioned.
But if you have a reference to the vector itself (or at least to it's begin() iterator), you can use:
int position = iter - v.begin();

Deleting items in foreach

Should you be allowed to delete an item from the collection you are currently iterating in a foreach loop?
If so, what should be the correct behavior?
I can take quite a sophisticated Collection to support enumerators that track changes to the collection to keep position info correct. Even if it does some compromisation or assumptions need to be made. For that reason most libraries simply outlaw such a thing or mutter about unexpected behaviour in their docs.
Hence the safest approach is to loop. Collect references to things that need deleting and subsequently use the collected references to delete items from the original collection.
It really depends on the language. Some just hammer through an array and explode when you change that array. Some use arrays and don't explode. Some call iterators (which are wholly more robust) and carry on just fine.
Generally, modifying a collection in a foreach loop is a bad idea, because your intention is unknown to the program. Did you mean to loop through all items before the change, or do you want it to just go with the new configuration? What about the items that have already been looped through?
Instead, if you want to modify the collection, either make a predefined list of items to loop through, or use indexed looping.
Some collections such as hash tables and dictionaries have no notion of "position" and the order of iteration is generally not guaranteed. Therefore it would be quite difficult to allow deletion of items while iterating.
You have to understand the concept of the foreach first, and actually it depends on the programming language. But as a general answer you should avoid changing your collections inside foreach
Just use a standard for loop, iterate through the item collection backwards and you should have no problem deleting items as you go.
iterate in reverse direction and delete item one by one... That should proper solution.
No, you should not. The correct behaviour should be to signal that a potential concurrency problem has been encountered, however that is done in your language of choice (throw exception, return error code, raise() a signal).
If you modify a data structure while iterating over its elements, the iterator might no longer be valid, which means that you risk working on objects that are no longer part of the collection. If you want to filter elements based on some more complex notation, you could do something like this (in Java):
List<T> toFilter = ...;
List<T> shadow;
for ( T element : toFilter )
if ( keep(element) )
shadow.add(element);
/* If you'll work with toFilter in the same context as the filter */
toFilter = shadow;
/* Alternatively, if you want to modify toFilter in place, for instance if it's
* been given as a method parameter
*/
toFilter.clear();
toFilter.addAll(shadow);
The best way to remove an item from a collection you are iterating over it to use the iterator explitly. For example.
List<String> myList = ArrayList<String>();
Iterator<String> myIt = myList.iterator();
while (myIt.hasNext()) {
myIt.remove();
}

Resources