在堆栈上分配一个小对象比在堆上创建它(一次)更有效吗

Is it more efficent to allocate a small object on the stack as apposed to creating it on the heap (once)?

本文关键字:创建 有效 一次 分配 堆栈 对象 一个      更新时间:2023-10-16

目前,在我编写的库中,我的小对象(不是多态的)在对象池中以unique_ptr的向量进行分配。现在很明显,我想改变这一点,因为这么多次打新电话显然有很多过头的地方。我很好奇是否更有效:将对象缓存在池中(将其存储在向量中,即vector<Object>),或者在需要时通过其ID创建对象。请注意,创建了很多对象。

我的意思是,我应该这样做吗:

需要时创建对象?(请注意,这些对象很小,64-128位,因为包含的只是一个ID和一个指向父对象的引用/指针)

Object ObjectFactory::create()
{
    return Object(nextId(), getParent());
}
Object ObjectFactory::get(unsigned id)
{
    return Object(id, getParent());
}

或:

Object& ObjectFactory::create()
{
     // get the next id of the object
     unsigned id = nextId();
     // resize (if necessary)
     if(_objects.size() <= id)
     {
        _objects.resize(id + 1);
        _objects[id]._parent = getParent();
     }
     return _objects[id];
}
Object& ObjectFactory::get(unsigned id)
{ return _objects[id]; }

我特别关心的是:Object的重新创建会引起太多的混乱吗?

@LokiAstari是对的,您的指针在调整大小时显然有问题。

有些事情我不明白;你说你正在使用一个对象池,但你有太多新语句的问题。如果你使用对象池,我会说这正是为了避免新的语句,不是吗?

以下是我的建议,尽管我不是专家,而且可能有更好的解决方案,通常涉及您自己的分配器的实现(力量的黑暗面..)。您可以使用像std::deque这样的容器,它可以确保指针/引用在调整大小时的有效性。

您将从大量对象(您的池)的初始大小调整开始,您可以在需要时手动处理后续的大小调整(使用预定义大小的块扩展容量),或者接受新语句,如果您知道不应该有很多,则使用template_back方法。

我也不知道你是否在用你的ID插入/删除很多对象。如果是这样,您可以考虑使用std::unordered_map

以下是使用std::deque:的示例

#include <iostream>
#include <deque>
#define POOL_RESERVE 1000

// Data storage for your object
struct MyObjectData
{
    double some_data;
};

// Container returned by the factory
struct MyObject 
{
    typedef MyObjectData data_type;
    unsigned   id; 
    data_type* data;
    MyObject(): id(0), data(0) {}
    MyObject( const unsigned& id_, data_type* data_ ): id(id_), data(data_) {}
    void set( const unsigned& id_, data_type* data_ )
        { id = id_; data = data_; }
};

// MyObject Pool
class MyObjectPool
{
public:
    typedef MyObjectData data_type;
    MyObjectPool(): count(0) { pool.resize(POOL_RESERVE); }
    void get( const unsigned& id, MyObject& obj )
        {
            // Check requested index
            if ( id >= count )
                obj.set( 0, 0 );
            else
                obj.set( id, &pool[id] );
        }
    void create( MyObject& obj )
        {
            // Create new data container if needed
            if ( count++ >= pool.size() ) pool.emplace_back();
            // Return next available object
            obj.set( count-1, &pool[count-1] );
        }
private:
    unsigned count;
    std::deque<data_type> pool;
};

// MyObject factory
class MyObjectFactory
{
    typedef MyObjectFactory self;
    static MyObject local;
    static MyObjectPool& get_instance()
        {
            static MyObjectPool pool; 
            return pool;
        }
public:
    static MyObject get( const unsigned& id )
        {
            self::get_instance().get(id,local);
            return local;
        }
    static MyObject create()
        {
            self::get_instance().create(local);
            return local;
        }
};
// Define static variable
MyObject MyObjectFactory::local = MyObject();

// Usage example
int main()
{
    MyObject a,b,c;
    a = MyObjectFactory::create();
    b = MyObjectFactory::create();
    c = MyObjectFactory::get(1);
}
相关文章: