Error with QMutableListIterator - qt

After appending an item to a QList which is pointed to by a QMutableListIterator, I find out the next value of the iterator points outside the list.
Or can't I point the iterator to any where in the list except the beginning or end?
Please I need help.

From the Qt documentation:
no changes should be done directly to the list while the iterator is active (as opposed to through the iterator), since this could invalidate the iterator and lead to undefined behavior.
Appending to the list might cause it's memory to be reallocated, which would mean that the iterator points to an invalid location.

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.

Hacking pointers in fortran

Let's consider a complex structure in fortran
TYPE ComplexStrType
! Static as well as dynamic memory defined here.
END TYPE ComplexStrType
Defined a physical space (allocated on the stack memory I think) to use two variables of ComplexStrType:
TYPE(ComplexStrType) :: SomeComplexStr
TYPE(ComplexStrType) :: AnotherComplexStr
TYPE(ComplexStrType),POINTER :: PointerComplexStr
Then, I use SomeComplexStr to define a few stuff in the stack and to allocate a big space in the dynamic memory.
Now, suppose I want to point AnotherComplexStr to SomeComplexStr and forget space I have defined in the stack memory to AnotherComplexStr. To do that I use a simple but useful trick which converts some variable in a Target:
FUNCTION TargComplexStr(x)
IMPLICIT NONE
TYPE(ComplexStrType),INTENT(IN),TARGET :: x
TYPE(ComplexStrType),POINTER :: TargComplexStr
TargComplexStr => x
END FUNCTION TargComplexStr
And then I point PointerComplexStr to SomeComplexStr:
PointerComplexStr => TargComplexStr(SomeComplexStr)
Finally, I do AnotherComplexStr equal to PointerComplexStr:
AnotherComplexStr = PointerComplexStr
After that, it's supposed SomeComplexStr as well AnotherComplexStr are pointing to the same static and dynamic memory.
The thing is:
How can I free the space used by AnotherComplexStr used when I defined it at the beggining?
How do you recomend me nullify the pointers?
Is that practice safe, or do I have to expect some strange memory leaks on the execution?
If it's possible, how can I point the "pointed variable" to its original form? (Just in case I have to use it again as normal variable)
NOTE: It's useful because at the execution we can be decided if we want to use AnotherComplexStr as what it is, a complex and allocated structure, or we can switch it to be treated as a pointer and points it to another thing which already has the information we need. If there is another and easy way to do that, please tell me.
The "trick" that you are using in TargComplexStr does not work the way you think - that function offers nothing useful over simple pointer assignment.
You can associate a non-TARGET actual argument with a TARGET dummy argument, as you are doing, but when the procedure with the TARGET dummy argument completes, any pointers that were associated with the dummy argument become undefined (F2008 12.5.2.4 p11).
(Pointers can only be associated with targets, therefore something that isn't a target cannot have a pointer associated with it.)
This means that the result of the function is a pointer with undefined association status. It is not permitted to return a pointer with undefined association status from a function (F2008 12.6.2.2 p4).
The pointer assignment statement would then make PointerComplexStr become an undefined pointer. PointerComplexStr is then referenced in the assignment to AnotherComplexStr. It is not permitted to reference a pointer with undefined association status (F2008 16.5.2.8 p1).
Intrinsic assignment creates a copy of a value. This is the case even if the object on the right is a pointer - a copy of the value of the target of that pointer is created. Intrinsic assignment does not, at the level of the top data object being assigned[1], make one variable reference the storage of another. As far as I can tell, the intent of your entire example code could be replaced by:
AnotherComplexStr = ComplexStr
If you are trying to do something different to that, then you need to explain what it is that you are trying to do.
[1]: If the type of an object being assigned is a derived type that has a pointer components, then the definition of the value of the object includes the pointer association status of the pointer component, but not the value of the target of the component itself (F2008 4.5.8).

Error with sequence argument when using QtConcurrent map

I'm trying to use QtConcurrent::map to run this function
//This function is used through QtConcurrent::map to create images from a QString path
void MainWindow::createQImage(QString* path) {
//create an image from the given path
QImage* t = new QImage(*path);
imageList->append(t);
}
on this container/sequence (declared in the mainwindow header and initialized in the mainwindow constructor)
QList<QImage *> *imageList = new QList<QImage *>;
Here's the code I'm trying to run
QFutureWatcher<void> futureWatcher;
futureWatcher.setFuture(QtConcurrent::map(imageList, &MainWindow::createQImage));
and here are the errors I'm getting:
request for member 'begin' in 'sequence', which is of non-class type 'QList<QImage*>*'
request for member 'end' in 'sequence', which is of non-class type 'QList<QImage*>*'
I need the "createQImage" function to be run for every element in "imageList," which can reach into the thousands. I believe the problem to be with the first parameter to the map function. And from what I've read, it may have to do with compatibility. There isn't much sample code online that I was able to relate to. I'm new to Qt and not the most experienced of programmers but I'd appreciate some help and feedback.
Alternatively, is there better way to do this using QtConcurrent?
Thanks in advance!
QtConcurrent::map wants a sequence as its first argument. You passed it a pointer to a sequence.
If you do
futureWatcher.setFuture(QtConcurrent::map(*imageList, &MainWindow::createQImage));
it should be happy.
Note that the compiler was reasonably clear about what the problem was. Take the time to read the errors carefully, they're usually not as cryptic as they perhaps at first seem. In this case it was telling you that the argument you passed was not of a class type. A quick look at the argument type at the end of the error reveals that it is a pointer.
QList, QImage, QString are Copy-On-Write types (see other Qt implicitly shared types), so you shouldn't use pointers to these types because they are basically already smart pointers.
And if you remove all pointers from your code, it should also fix the main problem.

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();

QT elements in vector initialization. How to solve private copy constructor problem?

I wanted to create a vector of a subclass of QGraphicsRectItem, named MyRect. This vector is initialized in MyClass:
MyClass::MyClass () : myVector_(80, std::vector<MyRect>(60, MyRect(true,true)))
...
I learned that vector constructs the first element and then copies it with the copy constructor. The problem is that QGraphicsRectItem's copy constructor is private and this doesn't work. (Very long error message, one hour of googling)
Now I have three possible solutions as I see it:
1.)Make a for-loop and populate myVector myself in the constructor body.
1b.) Just use regular array because it remains static anyway.
2.)Use MyRect* instead of MyRect as content of myVector (manual memory allocation -> bad)
3.)Use QVector that uses Object* by default and manages the memory for me.
After spending at least one hour on solving this I would like to hear from you if there are other good possibilities or what you think is the best solution. I am on the verge of dropping vectors for this and just using arrays.
The vector, as you declared it, will have to manipulate instances of MyRect. This means that depending of what you do the with the elements of the vector, or if you copy the vector, the MyRect instances might be duplicated.
This is not possible, because that would mean creating a new item each time a copy occurs (this is why the QGraphicsItem constructor is private). You have to manipulate the items of your scene through a pointer.
Thus, to me the best solution is to store in your vector pointers on your items (your 2nd solution) :
std::vector<MyRect*>
Memory management shouldn't be a problem at all, as this will be handled by Qt : when you destroy the scene, all items part of this scene will be destroyed.
Your vector won't duplicate items (no instanciation), only pointers, which means you won't create new items you'd have to destroy yourself.

Resources