假设我们有以下场景。
我们有一个ImageManager
类用于内部存储和管理图像数据。
这ImageManager
类有一个公共成员populateImage
,它将把图像读入内存,然后返回一个填充的MyImage
这是一个std::shared_ptr
周围Image
目的。该对象将包含一个uuid
它映射到由其管理的图像数据ImageManager
.
最后,我们定义一个回调函数,该函数在Image
析构函数并正确清理存储的图像数据ImageManager
.
这是示例:
#include <functional>
#include <vector>
#include <unordered_map>
#include <memory>
class Image {
public:
Image() = default;
~Image(){
if (m_deleter) {
m_deleter();
}
}
private:
friend class ImageManager;
std::function<void()> m_deleter = nullptr;
unsigned int m_uuid;
};
using MyImage = std::shared_ptr<Image>;
class ImageManager {
public:
void removeImage(unsigned int uuid) {
auto iter = m_imageMap.find(uuid);
if (iter == m_imageMap.end()) {
throw std::runtime_error("Unable to find image for UUID: " + std::to_string(uuid));
}
m_imageMap.erase(iter);
}
void populateImage(MyImage& image) {
image = std::make_shared<Image>();
static unsigned int uuid = 0;
++uuid;
image->m_uuid = uuid;
auto img = std::vector<uint8_t>(1000, 0);
m_imageMap[uuid] = img;
unsigned int currentUUID = uuid;
auto callbackFunc = [this, currentUUID]() {
this->removeImage(currentUUID);
};
image->m_deleter = callbackFunc;
}
private:
std::unordered_map<unsigned int, std::vector<uint8_t>> m_imageMap;
};
当我们的实例ImageManager
在我们的实例之前超出范围Image
,例如在以下驱动程序代码中:
int main() {
MyImage img1, img2;
{
ImageManager manager;
manager.populateImage(img1);
manager.populateImage(img2);
}
}
运行该程序打印:
terminate called after throwing an instance of 'std::runtime_error'
what(): Unable to find image for UUID: 2
但最终我明白这是未定义的行为this
指针指向m_deleter
不再指向有效的对象。
为了避免这个问题,正确的设计模式是什么?
整体设计有味道。如果ImageManager
是一个本地对象,并且MyImage
超出了范围,为什么需要删除地图中的项目?
不管怎样,我答应你展示共享/弱的习语。将地图包裹成shared_ptr
。这意味着地图将与 ImageManager 一起被销毁(如果您不复制此共享指针):
std::shared_ptr<std::unordered_map<unsigned int, cv::Mat>> m_imageMap;
在 lambda 中存储弱指针:
std::weak_ptr<std::unordered_map<unsigned int, cv::Mat>> weakPtr = m_imageMap;
auto callbackFunc = [weakPtr, uuid]() {
auto imageMap = weakPtr.lock();
if (imageMap)
auto iter = imageMap.find(uuid);
if (iter == imageMap.end()) {
throw std::runtime_error("Unable to find image for UUID: " + std::to_string(uuid));
}
imageMap.erase(iter);
}
};
image->m_deleter = callbackFunc;
弱指针将知道共享指针副本是否被销毁。
请记住,您不应该使用std::make_shared
在这种情况下:否则,只有当最后一个图像被销毁时,与地图关联的内存才会被释放。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)