C++ 在堆栈上分配一个小对象是否比在堆上创建它(一次)更有效?
目前,在我编写的库中,我的小对象(不是多态的)是在对象池中以C++ 在堆栈上分配一个小对象是否比在堆上创建它(一次)更有效?,c++,design-patterns,objectfactory,C++,Design Patterns,Objectfactory,目前,在我编写的库中,我的小对象(不是多态的)是在对象池中以unique\u ptr的向量分配的。现在很明显,我想改变这一点,因为在给new打这么多次电话时,显然有很多不理智的地方。我很好奇:缓存池中的对象(将其存储在向量中,即向量),或者在需要时通过其ID创建对象是否更有效。请注意,创建的对象很多 我的意思是,我应该这样做: 需要时创建对象?(请注意,这些对象很小,为64-128位,因为其中只包含一个ID和一个指向父对象的引用/指针) 或: Object&ObjectFactory::crea
unique\u ptr
的向量分配的。现在很明显,我想改变这一点,因为在给new打这么多次电话时,显然有很多不理智的地方。我很好奇:缓存池中的对象(将其存储在向量中,即向量
),或者在需要时通过其ID创建对象是否更有效。请注意,创建的对象很多
我的意思是,我应该这样做:
需要时创建对象?(请注意,这些对象很小,为64-128位,因为其中只包含一个ID和一个指向父对象的引用/指针)
或:
Object&ObjectFactory::create()
{
//获取对象的下一个id
无符号id=nextId();
//调整大小(如有必要)
如果(_objects.size()@LokiAstari是正确的,那么很明显您在调整大小时的指针有问题
有件事我不明白,你说你在使用对象池,但是你对太多的新语句有问题。如果你在使用对象池,我会说这恰恰是为了避免新语句,不是吗
以下是我的建议,虽然我不是专家,可能有更好的解决方案涉及到您自己的分配器的实现(通常是原力的黑暗面)。您可以使用像std::deque
这样的容器,以确保调整大小时指针/引用的有效性
您可以从许多对象(您的池)的初始调整开始,并且可以在需要时手动处理后续调整(使用预定义大小的块扩展容量),或者如果您知道不应该有很多对象,则接受新语句,并使用emplace_back方法
我也不知道你是否用IDS做了很多插入/删除对象。如果是这样,你可以考虑使用<代码> STD::unOrdEdEdMult < /P>
下面是一个使用
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);
}
#包括
#包括
#定义池_储备1000
//对象的数据存储
结构MyObjectData
{
将一些数据加倍;
};
//工厂退回的集装箱
结构对象
{
typedef MyObjectData_type;
无符号id;
数据类型*数据;
MyObject():id(0),数据(0){}
MyObject(const unsigned&id_,data_type*data_):id(id_),data(data_){
无效集(常量无符号和id,数据类型*数据)
{id=id;data=data}
};
//MyObject池
类MyObjectPool
{
公众:
typedef MyObjectData_type;
MyObjectPool():计数(0){pool.resize(pool_RESERVE);}
void get(const unsigned&id、MyObject&obj)
{
//检查请求的索引
如果(id>=计数)
对象集(0,0);
其他的
对象集(id和池[id]);
}
创建空洞(MyObject和obj)
{
//如果需要,创建新的数据容器
如果(count++>=pool.size())pool.emplace_back();
//返回下一个可用对象
对象集(count-1和pool[count-1]);
}
私人:
无符号计数;
标准:德克池;
};
//MyObject工厂
类对象工厂
{
typedef myobject-factory-self;
静态肌体局部;
静态MyObjectPool&get_实例()
{
静态对象池;
回流池;
}
公众:
静态MyObject get(const unsigned&id)
{
self::get_instance().get(id,local);
返回本地;
}
静态MyObject创建()
{
self::get_instance().create(本地);
返回本地;
}
};
//定义静态变量
MyObject MyObjectFactory::local=MyObject();
//用法示例
int main()
{
对象a、b、c;
a=MyObjectFactory::create();
b=MyObjectFactory::create();
c=MyObjectFactory::get(1);
}
这个问题缺少一个细节:当您运行这两个版本时,一个版本的开销是否太大了?让我们暂时假设堆的速度比堆栈慢100倍。您的应用程序是否经常这样做,以至于它注意到了这一差异?如果不是,是否更重要的是拥有一个干净、易于使用和维护的界面?存储连续内存中的对象(std::vector保证)可以给您带来巨大的速度提升,而不是将它们存储在内存的碎片区域。我会担心这一点\u objects.resize(id+1)
。\u对象的类型是什么?
?resize将移动所有成员,从而使以前返回的所有引用无效!@miguel.martin:因为它是一个向量。调用resize()时,肯定有可能移动内部数据。如果发生这种情况,则所有引用(和迭代器)都将被移动你之前返回的是无效的。为什么要使用std::deque
而不是std::vector
?我想我可能会使用我选择使用的第二个选项。顺便说一句,我认为你根本不需要使用单例,只是我的意见。正如我所说,std::vector
不能确保调整大小后指针/引用的有效性或者一个push_back
,这就是为什么你需要使用std::deque
。我认为单例是必要的,因为一个池应该是可以访问的,而不需要明确地传递工厂的引用(顺便说一句,这是不清楚和危险的);任何函数或方法都应该能够事先访问池中的对象,即使我不知道您的程序。如果您的factory被意外复制,会发生什么?您是否阅读了@LokiAstari的注释?您的第二个解决方案无效。@Sh3john,我读到了。.只是不知道它在调整大小并向后推时在内部移动了对象。安d还有……这不是你让工厂不可复制的原因吗?@miguel.martin这是一种确保它确实不被复制的方法。但是想想abo
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]; }
#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);
}