【问题标题】:Contiguous Memory连续内存
【发布时间】:2017-07-24 13:15:06
【问题描述】:

所以我在一大组对象上执行相同的功能。据我了解,最好将这组对象保存在连续的内存空间中以获得更好的时间。

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

注意:myObjects 在应用程序的整个生命周期内都存在,并且不断变化。

在我的代码的其他部分,我想直接使用MyObject 的单个实例。通常我会用MyObjectManager 之类的类包装我的向量并制作一个吸气剂:

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

但这很容易出错,因为如果调整向量的大小,指针可能会失效。这让我只能使用索引或 ID,并通过管理器实现所有更改

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

但我不认为这是最好的方式,因为它紧密结合了我的经理和对象类。所以我想为经理的朋友创建一个接口:

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" );

注意:请原谅代码中的问题。这更多是关于想法而不是关于代码。

虽然这似乎可行,但我很好奇我是否正确地推理了这个问题,以及这个解决方案是否过于复杂?希望得到一些见解,谢谢。

【问题讨论】:

  • 您是否有多个线程同时修改向量?如果不是,那么您不必担心在向量中使用指向对象的指针,只要在对向量执行可能导致重新分配的操作之前取消引用它们即可。
  • 另外,“如果调整向量大小,指针可能会失效” - 所需容量是否会发生如此剧烈的变化,以至于您不想.reserve() 最大预先,从而避免重新分配?
  • 你会经常做for( auto const&amp; obj listMyObjects ) { obj.doThing(); } 吗?如果不是,您可以考虑使用std::list,它不会使迭代器/对其他元素的引用无效。 This 也可能有帮助。
  • “据我了解,最好将这组对象保存在连续的内存空间中以节省时间。” 您是否进行了基准测试,或者您是否完全基于此设计假设?
  • 如果你的代码对性能问题很敏感,在未排序的顺序数据上调用类似 myObjects.find(name) 的东西会严重影响性能。使用 map 或 unordered map 将是一个更好的选择,另外还可以让您摆脱容器重新分配的问题。

标签: c++ c++11 memory optimization


【解决方案1】:

出于您给出的原因,我认为使用索引或 id 而不是指针来对向量中的对象进行长期引用是合理的。我认为将 id 包装在一个类中以提高类型安全性也是合理的。

但我通常不会让该类成为真实对象的完整代理。如果vector 真的从多个线程“不断地”改变,那么甚至像

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

不安全。在使用 at 获取对对象的引用和设置名称之间,vector 可能已调整大小并且您的引用可能无效。

您通常需要在性能关键代码中进行一些本地保证,即vector 不会被调整大小并且使用引用或指针是安全的。无论如何,在紧密循环中按 id 查找对象的成本可能会超过您从数据本地化获得的任何好处。

过度使用MyObjectInterface 可能会成为数据局部性的敌人,因为与MyObject 不同,它们不能保证在内存中是连续的。

如果实际上需要MyObjectInterface 和/或MyObjectManager 来提供复杂的同步机制,那么我建议您发布一个单独的问题,其中包含该机制。

【讨论】:

    猜你喜欢
    • 2014-03-28
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2012-01-08
    • 2015-11-04
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多