在堆栈上分配一个小对象而不是在堆上创建它(一次)是否更有效?

时间:2013-02-05 12:33:30

标签: c++ design-patterns objectfactory

目前,我编写的库中,我的小对象(非多态)在一个对象池中被分配到一个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的重新创造是否会引起很多人的反对?

1 个答案:

答案 0 :(得分:0)

@LokiAstari是对的,你显然有关于调整大小的指针有问题。

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

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

您将首先调整大量对象(您的池)的初始大小,然后您可以在需要时手动处理后续调整大小(使用预定义大小的块扩展容量),或接受新语句然后如果您知道不应该有很多,并使用emplace_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);
}