Continuous memory

So, I am performing the same function on a large set of objects. As far as I understand, it is better to store this set of objects in contiguous memory space for better timing.

std::vector<MyObject> myObjects;
// Fill vector with thousands of objects
for( auto const& obj listMyObjects ) { obj.doThing(); }

      

Note. myObjects

lives during the lifetime of the application and is constantly changing.

In other parts of my code, I want to work directly with one instance MyObject

. Usually I would wrap my vector with a type class MyObjectManager

and create a getter:

MyObject * obj = MyObjectManager::getObject( "OBJECT_NAME" );
obj->setName( "NEW_NAME" );

      

But this is error prone as the pointer may not be valid if the vector is changed. This results in me using the index or id instead and doing all the changes with the manager

int objId = MyObjectManager::getObject( "OBJECT_NAME" );
MyObjectManager::setObjectName( objId, "NEW_NAME" );

      

But I don't feel like this is the best way as it tightly connects my manager and object class. So I thought about creating an interface for objects that is a friend of the manager:

class MyObject
{
    std::string myName;
}

class MyObjectInterface
{
    int myId;

    MyObjectInterface( int id ) { myId = id; }
    void setName( std::string name ) { MyObjectManager::myObjects.at( myId ).name = name; }
}

class MyObjectManager
{
    friend class MyObjectInterface;
    static std::vector<MyObject> myObjects;

    static MyObjectInterface getObject( std::string name ) { return MyObjectInterface( myObjects.find( name ) ); // Psuedo code }
}

MyObjectInterface obj = MyObjectManager::getObject( "OBJECT1" );
obj.setName( "OBJECT2" );

      

Note. Sorry for the mistakes in the code. It's more about the idea, namely the code.

While this seems to work, I'm curious if I was reasoning about the problem correctly and is it over complicating this solution? Love some understanding, thanks.

+3


source to share


1 answer


I think it is wise to use an index or id instead of a pointer for long lived references to objects in a vector for the reasons you give. I think it is also wise to wrap this identifier in a class for more type safety.

But I usually couldn't make this class a complete proxy for a real object. If it vector

really changes "constantly" from several threads, then even something like

MyObjectManager::myObjects.at( myId ).name = name;

      

unsafe. Between getting a reference to an object using at

and setting the name, the size vector

may have changed and your reference may be invalid.



Typically, performance critical code requires a local guarantee so that the size is vector

not resized and references or pointers can be used. The cost of finding objects by ID in a tight loop probably outweighs all the benefits you get from data location anyway.

Overuse MyObjectInterface

is likely to be the enemy of data locality, given that unlike MyObject

they are not guaranteed to be contiguous in memory.

If MyObjectInterface

and / or are MyObjectManager

really needed to create a complex synchronization mechanism, I suggest you post a separate question that includes this.

+4


source







All Articles