Reputation: 624
I have an application which contains instances of an class Obj
with each instance identified by an ID integer as a class members. The objects are arranged as a top level object with branches of nested sub-objects stored in a std::vector
like this:
/* Obj tree with L ID as:
*
* Obj (L 0)
* |
* Obj (L 1)
* |
* Obj (L 2)
*
*/
I have defined a utility method to redirect a pointer to an object in the hierarchy that has a given ID. This is implemented as a recursive call to the utility from each object with sub-objects until the object is found or the bottom of the hierarchy has been reached. The recursion should then unroll and return the pointer to the application scope. For this reason I have passed the pointer as a reference so it may be changed within the appropriate recursive call.
Source code is as follows:
The Object class is
// Object class
class Obj {
friend class Utils;
friend class App;
public : Obj(int ID_L) // Overloaded constructor
{
this->ID_L = ID_L;
}
// Public and private IDs
public : int ID_L;
// Vector of sub objects
std::vector<Obj> subObj;
// Add sub-obj method
public : void addSubObj(int num_layers) {
// Add the sub-obj
subObj.emplace_back( this->ID_L + 1);
// Add one underneath if necessary
if (subObj.back().ID_L <= num_layers) {
subObj.back().addSubObj(num_layers - 1);
}
};
};
The Utility class is
// Utility class
class Utils {
// Static method to return pointer to obj in the hierarchy
public : static void getObj(Obj*& ObjTree, int ID_L, Obj*& ObjRet) {
// Try match on the top of the tree given
if (ObjTree->ID_L == ID_L) {
ObjRet = ObjTree; // Match found so update pointer and return
return;
} else {
// Loop through array of subObjs on this Obj
for (Obj o : ObjTree->subObj) {
// Create pointer to object in present scope
Obj* O = &o;
// Look for match on this subObj
Utils::getObj(O, ID_L, ObjRet); // Recursvie call passing reference of pointer along and address of present sub-Obj and its children
// If a match found then return the non-null pointer
if (ObjRet != NULL) {
return;
}
}
}
// Specified Obj has not been found in the tree
return;
}
};
The application class is
// Application class
class App {
public : void run () {
// Create object tree as above
Obj TopObj(0); // Top level obj
TopObj.addSubObj(2); // Left side branch
// Create pointer to Obj to do further stuff with
Obj* _o;
// Create pointer to tree
Obj* Tree = &TopObj;
// Loop over all desired ID combos and return pointer to appropriate Obj in hierarchy
for (int l = 0; l <= 2; l++) {
// Null the pointer in preparation for next Obj
_o = NULL;
// Try to fetch a particular Obj from ObjTree
Utils::getObj(Tree, l, _o);
// If pointer is not null then Obj has been found so try to read IDs from it
if (_o != NULL) {
std::cout << "FOUND -- L" << l << " : reading ID from pointer as L" << _o->ID_L << " : " << _o << std::endl;
}
}
}
};
And the entry point is here:
// Entry point
int main(int argc, char* argv[]) {
// Start application
App a;
a.run();
}
When debugging I have written out the value of the pointer _o
to the screen and I can see it change when the object is found and then maintain its value as the recursion unrolls. However When trying to access the object to which it points to print out the ID to the screen in application scope the numbers are junk. This is the case when the object has been found 2 layers deep into the hierarchy or more. It does work when only drilling down one level.
Since I passed the pointers as references I was confident that they will be carried through scope but that doesn't seem to be the case as it seems like the object is going out of scope.
Can anyone see the problem with this implementation and perhaps suggest an improved implementation for such an object retrieval utility?
Upvotes: 0
Views: 1169
Reputation: 217810
In
for (Obj o : ObjTree->subObj) {
Utils::getObj(&o, ID_L, ID_R, ObjRet);
You make a copy of Obj
and ObjRet
may have dangling pointer once leaving scope.
use instead:
for (Obj& o : ObjTree->subObj) {
Utils::getObj(&o, ID_L, ID_R, ObjRet);
Upvotes: 2