Search code examples
c++vectorreferencetypedefencapsulation

Writing C++ API - how to keep external references to API internal objects?


So I'm writing an API in C++ to be used in another GUI application I'll be writing. The API will allow the user to create instances of "MyObject" and modify the properties of that object, but the object itself will not be exposed to the client, only an ID to that object. So for instance:

Object_ID identifier = myApiCreateObject();
myApiModifyProperty(identifier, "PROPERTY_NAME", "value");

So the identifier acts as an external handler to a specific MyObject instance.

As of right now the Object_ID is defined as follows:

typedef int Object_ID;

Currently all MyObject instances are stored in an std::vector within my API. The Object_ID is simply the index in the vector that the desired instance lives.

The problem with this approach is that I don't know how to handle deleting instances of MyObject from the vector. For instance, let's say I have 10 instances of MyObject created and I want to delete the instance at index 5, I would want to do something like the following:

myApiDeleteObject(handlerForIndex5);

By doing this though, internally my API would remove that object from the std::vector and then would have to shift over all the objects at indices > 5. This would cause my external handlers to no longer reference the correct object.

So just using the index of the array by itself is not sufficient, but I don't know of a better alternative without having to expose the MyObject class to the client.

EDIT

Here's an updated example highlighting the issue at hand:

Internally the API performs certain algorithms on the list of objects, some of these algorithms require sorting the vector as a step.

So my GUI would do something like :

myApiBeginCalculations(); 

and then internally the API would be doing something like this:

myApiBeginCalculations()
{ 
     //Start algorithm
     .......
     Sort(vector);
    //Continue with algorithm
}

Then let's say after that algorithm is complete, the user wants to modify a given MyObject instance and start again:

myApiBeginCalculations();
myApiModifyProperty(myHandler, "PROPERTY", "VALUE");
myApiBeginCalculations();
myApiDeleteObject(myHandler); 
myAPiBeginCalculations();

Internally myApi will be doing a bunch of things to the MyObject instances and I need a reliable way to keep track of individual instances on the client even as they get shuffled around.


Solution

  • You need to use an ID based on something that is both unique for each object and which remains constant for each object. Clearly an index into a vector you're continually rearranging does not qualify.

    You haven't described the properties of the objects so I can't say whether there's something already suitable for this use, but if not then you can add something. You can assign an IDs to each object as you create them, or you could allocate the objects on the heap so that their addresses remain consistent as you, for example, sort a vector<unique_ptr<MyObject>>.

    You'll have to consider each operation you need to perform and figure out the necessary performance. For example a linear search through the vector in order to find an object with a matching ID may be too slow for some purpose. In that case you'll have to figure out how to avoid that linear search, perhaps by keeping a map on the side or something, at the cost of having to keep the map updated during other operations.