在表演之前人们把我的脑袋扯下来:是的,在问这个之前我已经做了分析:)
我再次查看我的容器类型之一,虽然我有一个可行的解决方案,但性能很差,因为缓存的每种类型的项目都会导致堆上的单独分配(这当然很昂贵)。
基于对我的程序输入的静态分析,我想出了一种方法来了解所有可能放入我正在传递的缓存对象中的对象所需的总大小。基本上,我有一个可以在给定缓存对象中构造的对象列表,所以我知道我可能需要缓存的大小是多少,但不是在编译时——仅在运行时。
基本上,我想做的是boost::make_shared
——获取一个内存块,并shared_ptr
在同一个内存块中构造位以及受控对象。
我不必担心保留复制行为,因为缓存对象是不可复制的,并且由客户端通过指针传递(它通常存储在 aptr_vector
或 a之类的东西中std::auto_ptr
)。
但是,我不熟悉如何实现这样的容器,即如何遵循对齐限制等。
在伪代码中,我想做的是:
//I know a lot of what's in here is not portable -- I need to run only on x86
//and x64 machines. Yes, this couple of classes looks hacky, but I'd rather
//have one hacky class than a whole programfull :)
class CacheRegistrar
{
//Blah blah
public:
//Figures out what objects will be in the cache, etc
const std::vector<std::size_t>& GetRequiredObjectSizes() const;
//Other stuff...
template <typename T>
void RegisterCacheObject();
template <typename T>
std::size_t GetObjectIndex() const;
// etc.
};
class CacheObject;
std::auto_ptr<CacheObject> CacheObjectFactory(const CacheRegistrar& registrar)
{
//Pretend this is in a CPP file and therefore CacheObject is defined...
const std::vector<size_t>& sizes(registrar.GetRequiredObjectSizes());
std::size_t sumOfCache = std::accumulate(sizes.begin(), sizes.end());
sumOfCache += sizeof(CacheObject);
boost::scoped_array<char> buffer(new char[] sumOfCache);
CacheObject *obj = new (reinterpret_cast<void *>(buffer.get())) CacheObject;
buffer.release(); //PSEUDOCODE (boost::scoped_array has no release member);
return std::auto_ptr<CacheObject>(obj); //Nothrow
}
class CacheObject
{
CacheRegistrar *registrar; //Set by my constructor
public:
template<typename T>
T& Get()
{
char * startOfCache = reinterpret_cast<char *>(this) +
sizeof(CacheObject);
char * cacheItem = startOfCache + registrar->GetObjectIndex<T>();
return *reinterpret_cast<T*>(cacheItem);
}
};
我的一般概念在这里合理吗?有没有更好的方法来做到这一点?