There is no way, in general, to find a C++ class instance by knowing the
value of one of its data members, for two reasons:
The most typical way of solving this problem is to build some sort of
container in advance that has all of the instances you want to search
through.
One approach: use std::map
For example, if there is an existing function that creates objects:
convoy_t *makeConvoy(...)
{
convoy_t *convoy = new convoy_t(...);
// maybe do other things
return convoy;
}
then you can modify this code to keep track of all of the objects by
first creating a container, for example a
std::map
. For
simplicity we'll make it at file scope, but there may be a better place
to put it in the real program:
#include <map> // std::map
#include <utility> // std::make_pair
// Map from convoy ID to a pointer to the instance.
std::map< int, convoy_t* > convoyMap;
Then, in makeConvoy
, before the return
, add code that inserts it
into the map:
// This uses the "traditional" insertion syntax. See notes below.
convoyMap.insert(std::make_pair(
convoy->getID(), // key
convoy)); // value
Finally, when you have an ID and want its convoy, look up the ID in the
map using the at
method:
convoy_t *convoy = convoyMap.at(ID);
Some notes:
You need to ensure IDs are unique. If they aren't, then when you try
to add the second object with the same ID into the map, the
insert
call will not do anything (see linked reference for details).
The at
method will throw
std::out_of_range
if the ID is not found. You should write an exception handler to deal
with that possibility.
The call to insert
can also be written using a more compact
notation that takes advantage of initializer lists, introduced with
C++11: convoyMap.insert({convoy->getID(), convoy});
.
If an object is
deleted,
then it must also be removed from the map. Otherwise, the pointer in
the map will "dangle", meaning it points at memory that will
subsequently be reused for another purpose, leading to all sorts of
problems.
If the ID of an object changes, then you have to remove it from the map and re-insert it with the new ID. The map itself has no knowledge that the ID used as a key is meant to be the same as the data member value.
Complete example
Here is a complete program demonstrating the above technique:
// convoy.cc
// Demonstrate finding objects by ID.
#include <cassert> // assert
#include <map> // std::map
#include <utility> // std::make_pair
int nextConvoyID = 1;
class convoy_t {
public: // instance data
int m_id;
int m_otherData;
public: // methods
convoy_t(int id, int otherData)
: m_id(id), m_otherData(otherData) {}
int getID() const { return m_id; }
};
// Map from convoy ID to a pointer to the instance.
std::map< int, convoy_t* > convoyMap;
convoy_t *makeConvoy(int otherData)
{
int id = nextConvoyID++;
convoy_t *convoy = new convoy_t(id, otherData);
if (false) {
// Traditional syntax.
convoyMap.insert(std::make_pair(
convoy->getID(), // key
convoy)); // value
}
else {
// More compact notation using an initializer list.
convoyMap.insert({convoy->getID(), convoy});
}
return convoy;
}
int main()
{
// Make some convoys.
convoy_t *c1 = makeConvoy(11);
convoy_t *c2 = makeConvoy(12);
convoy_t *c3 = makeConvoy(13);
// Get one of the IDs.
int id = c2->getID();
// Amnesia strikes! Where did 'id' come from?
convoy_t *convoy = convoyMap.at(id);
// Ah, there it is.
assert(convoy == c2);
return 0;
}
// EOF
There may already be a container you can use
You say you're working in Simutrans Extended. I don't know anything
about it, but as was noted in the comments, it seems to have a
world
object that can be
traversed:
// loop through all convoys
for (vector_tpl<convoihandle_t>::const_iterator i = world->convoys().begin(), end = world->convoys().end(); i != end; i++)
{
current_convoy = *i;
// only consider lineless convoys which support this compartment's goods catetory
if ( !current_convoy->get_line().is_bound() && current_convoy->get_goods_catg_index().is_contained(catg) )
{
temp_linkage.convoy = current_convoy;
linkages->append(temp_linkage);
transport_index_map[ 65536u + current_convoy.get_id() ] = linkages->get_count();
}
}
Looping through all convoys in order to find one with a particular ID is
not very efficient, but it may suffice for what you're doing. There might also be a map of conveys already existing; like I say, I don't know that program.