Reputation: 718
I have the following structure on the software I am developing:
ClassA:
QHash<int, ClassB>
ClassB:
QHash<int, ClassC>
ClassC:
QMap<ID, QSharedPointer<ClassD> > (this is because I need to have the items ordered)
QHash<int, QSharedPointer<ClassD> > (this exists so I can access an item via id)
My question is if it is safe to have a pointer, that will be edited, to an element inside a data structure. I have been getting errors while trying to debug in which the debugger is unable to stop at a break point and I get a SIGTRAP error, but I am not sure if it is related to a memory issue on this.
To give a better example, related to the software I'm developing I have a QHash<int, Take>
that represents a list of videos. The user will be editing only one video at a time, so I have a pointer to the current video, which is a Take inside the Hash. Each Take has a bunch of parameters that can be edited but the most common is a QMap of Notes. Is is safe to do something like this?
Take *currentTake = &takes[currentTakeId];
----//---
currentTake->addNote(new Note());
currentTake->changeSomeParameter();
etc
Upvotes: 5
Views: 978
Reputation: 72054
Whether (or how long) it is safe to keep a pointer/reference to an element of a collection is up to that collection. For example, a std::vector
invalidates all pointers into it on reallocation, and removal/insertion without reallocation invalidates (well, changes what they point to) all pointers beyond the insertion/removal point. A std::list
on the other hand is stable; pointers only get invalidated if the specific element they point to is removed.
A collection should generally document its invalidation behavior. Unfortunately, the Qt collections don't. Reading their documentation tells us that QMap
is a red-black balanced binary tree, and QHash
is a separate chaining hash table, so they should both have the std::list
behavior for invalidation, but there's no guarantee of that. (For example, QHash
could store the head entry directly in the bucket list, which would mean that rehashing would invalidate most pointers, and removing an element could invalidate pointers to elements in the same bucket.)
Upvotes: 5
Reputation: 4036
Use references, the data container of your example is storing values of object and returns reference to the object when you do takes[currentTakeId]
.
You can do this
Take ¤tTake = takes.value(currentTakeId]);
// same as 'takes[currentTakeId]'
// but avoid to create empty element if 'currentTakeId' has no element
----//---
currentTake.addNote(new Note());
currentTake.changeSomeParameter();
// do not change 'takes' as long as you use 'currentTake'
Your idea is fine (and more or less the same), you can retrieve the address and work on the pointer as long as the container is not modified when you are using this pointer. Because the data container might copy your element if resizing, or delete it, and then the pointer would be invalid.
If your objects Take are quite big you can lose performance because of the copy when the container is resized or passed by value (and copied). Then storing pointer can be a solution, or use the implicit sharing pattern of Qt on your data class.
Upvotes: 0