Solidus
Solidus

Reputation: 718

Is it safe to have pointers to elements in Data Structures? (c++ with QT)

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

Answers (2)

Sebastian Redl
Sebastian Redl

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

ymoreau
ymoreau

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 &currentTake = 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

Related Questions