在表演之前,人们撕开了我的头:是的,我在问这个:)之前已经进行了分析::)

我再次看着我的 类型容器之一, ,尽管我有一个可行的解决方案,但性能很差,因为缓存的每种类型的项目都会在堆上单独分配(当然很昂贵)。

基于对程序输入的静态分析,我发现了一种方法,可以知道所有可能放在我的缓存对象中所需的对象所需的总尺寸。基本上,我有一个可以在给定的缓存对象中构造的对象列表,因此我知道我可能要提前缓存的大小,但不在编译时 - 仅在运行时。

基本上,我想做的是 boost::make_shared 确实 - 获取一个内存块,并构造 shared_ptr 位以及同一内存块中的受控对象。

我不必担心保留复制行为,因为缓存对象是不可复制的,并且由客户指针传递(通常存储在类似的东西中 ptr_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);
    }
};

我的一般概念在这里听起来吗?有更好的方法吗?

有帮助吗?

解决方案

但首先,阅读 这篇文章Andrei Alexandrescu 关于他认为他应该在该章中写的内容 - 一种使用 堆层 (真的是你的)。我用堆层建造 , 死硬死硬的顽固的, , 和 迪哈德, ,以及我们的OOPLSA 2002论文中使用的自定义分配器, 重新考虑自定义内存分配, ,在开始创建自定义分配器之前,您也应该阅读。

其他提示

查看Loki小对象分配器。

快速竞争不会产生任何直接面向人类的文档。有Doxygen生成的文档,但并非特别可抓。但是,在Andrei Alexandrescu的“现代C ++设计”中记录了设计和实施。

如果您只想有效地回收给定类的对象,请考虑一个简单的自由列表 - 可能是一个自由列表的原始存储块。

欢呼和hth。

我看到的关键问题是返回

auto_ptr

对于以非默认方式分配的记忆。您可以通过定义合适的过载删除来解决此问题,但最好将自己的销毁功能定义为工厂的一部分。如果执行此操作,您还将内部内存管理本地化在缓存类中,从而使您有更多自由来提高该类别的本地性能。如果当然,使用智能指针来控制内存管理是一个好主意;您需要做的是定义自己的分配器并定义SMART_PTR来使用它。

作为参考,管理自定义分配的另一种方法是定义自定义新运算符。即这种事情:

struct Cache
{
    void* allocate(size_t size)
    {
        size_t blockSize = sizeof(size_t) + size;
        // Placeholder: do what ever appropriate to blocks of size 'blockSize'
        return malloc(blockSize);
    }
    void destroy(void* p)
    {
        size_t* block = reinterpret_cast<size_t*>(p);
        size_t blockSize = *block;
        // Placeholder: do what ever appropriate to blocks of size 'blockSize'
        free(p);
    }

};
Cache cache;


void* operator new (size_t size, Cache& cache )
{
    return cache.allocate(size);
}

struct CacheObject 
{
    void operator delete(void* p)
    {
        cache.destroy(p);
    }
};


CacheObject* co = new (cache) CacheObject;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top