gpt4 book ai didi

c++ - 如何使用 std::shared_ptr 实现缓存管理器?

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:08:14 25 4
gpt4 key购买 nike

#include <mutex>
#include <assert.h>
#include <iostream>
#include <unordered_map>
#include <memory>
#include <string>
#include <stdio.h>

//
// Requirements:
// 1: the bitmap could be used by multiple thread safely.(std::shared_ptr could?)
// 2: cache the bitmap and do not always increase memeory
//@NotThreadSfe
struct Bitmap {
public:
Bitmap(const std::string& filePath) {
filePath_ = filePath;
printf("foo %x ctor %s\n", this, filePath_.c_str());
}
~Bitmap() {
printf("foo %x dtor %s\n", this, filePath_.c_str());
}
std::string filePath_;
};

//@ThreadSafe
struct BitmapCache {
public:
static std::shared_ptr<Bitmap> loadBitmap(const std::string& filePath) {
mutex_.lock();

//whether in the cache
auto iter = cache_.find(filePath);
if (iter != cache_.end()) {
if ((*iter).second) {
return (*iter).second;
} else {
std::shared_ptr<Bitmap> newPtr(new Bitmap(filePath));
(*iter).second = newPtr;
return newPtr;
}
}

//try remove unused elements if possible
if (cache_.size() >= kSlotThreshold) {
std::unordered_map<std::string,std::shared_ptr<Bitmap>>::iterator delIter = cache_.end();
for (auto iter = cache_.begin(); iter != cache_.end(); ++iter) {
auto& item = *iter;
if (item.second && item.second.use_count() == 1) {
delIter = iter;
break;
}
}
if (cache_.end() != delIter) {
(*delIter).second.reset();
cache_.erase(delIter);
}
}

//create new and insert to the cache
std::shared_ptr<Bitmap> newPtr(new Bitmap(filePath));
cache_.insert({filePath, newPtr});
mutex_.unlock();
return newPtr;
}
private:
static const int kSlotThreshold = 20;
static std::mutex mutex_;
static std::unordered_map<std::string,std::shared_ptr<Bitmap>> cache_;
};

/* static */
std::unordered_map<std::string,std::shared_ptr<Bitmap>> BitmapCache::cache_;

/* static */
std::mutex BitmapCache::mutex_;

int main()
{
//test for remove useless element
char buff[200] = {0};
std::vector<std::shared_ptr<Bitmap>> bmpVec(20);
for (int i = 0; i < 20; ++i) {
sprintf_s(buff, 200, "c:\\haha%d.bmp", i);
bmpVec[i] = BitmapCache::loadBitmap(buff);
}
bmpVec[3].reset();
std::shared_ptr<Bitmap> newBmp = BitmapCache::loadBitmap("c:\\new.bmp");

//test for multiple threading...(to be implemenetd)
return 0;
}

我是 C++ 内存管理的新手。您能否给我一个提示:我的方法是否正确,或者我应该采用不同的设计策略或不同的内存管理器策略(例如 weak_ptr 等)?

最佳答案

这让我想起了 Herb Sutter 的 "Favorite C++ 10-Liner"在 GoingNative 2013 上的演讲,稍作改编:

std::shared_ptr<Bitmap> get_bitmap(const std::string & path){
static std::map<std::string, std::weak_ptr<Bitmap>> cache;
static std::mutex m;

std::lock_guard<std::mutex> hold(m);
auto sp = cache[path].lock();
if(!sp) cache[path] = sp = std::make_shared<Bitmap>(path);
return sp;
}

评论:

  1. 始终使用 std::lock_guard 而不是在互斥锁上调用 lock()unlock()。后者更容易出错并且不是异常安全的。请注意,在您的代码中,前两个 return 语句从未解锁互斥量。
  2. 这里的想法是使用缓存中的 weak_ptr 跟踪已分配的位图对象,因此缓存从不 自行保持位图处于事件状态。这消除了手动清理不再使用的对象的需要 - 当引用它们的最后一个 shared_ptr 被销毁时,它们会自动删除。
  3. 如果 path 以前从未见过,或者相应的 Bitmap 已被删除,cache[path].lock() 将返回一个空 shared_ptr;下面的 if 语句然后使用 make_shared 加载 Bitmap,将生成的 shared_ptr 移动分配到 sp ,并设置 cache[path] 以跟踪新创建的位图。
  4. 如果path对应的Bitmap还活着,那么cache[path].lock()会创建一个新的 shared_ptr 引用它,然后返回。

关于c++ - 如何使用 std::shared_ptr 实现缓存管理器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24379786/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com