c++ - 使用 std::make_shared 后可以缓存吗?
问题描述
我正在阅读 Effective Modern C++ (Scott Meyers) 并尝试第 21 项中的一些内容。这本书说使用的副作用是在所有s 和s 都消失std::make_shared
之前无法释放内存(因为控制块与内存一起分配)。shared_ptr
weak_ptr
我预计这将意味着如果我保留一个缓存来保存一堆weak_ptr
s,那么就不会释放任何内存。我使用下面的代码进行了尝试,但是由于从向量中删除了 shared_ptrs,我可以使用 pmap 看到实际上正在释放内存。谁能解释我哪里出错了?或者如果我的理解是错误的?
注:loadWidget
本实验的目的与书中的功能不同。
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
#include <thread>
#include <chrono>
class Widget {
public:
Widget()
: values(1024*1024, 3.14)
{ }
std::vector<double> values;
};
std::shared_ptr<Widget> loadWidget(unsigned id) {
return std::make_shared<Widget>();
}
std::unordered_map<unsigned, std::weak_ptr<Widget>> cache;
std::shared_ptr<Widget> fastLoadWidget(unsigned id) {
auto objPtr = cache[id].lock();
if (!objPtr) {
objPtr = loadWidget(id);
cache[id] = objPtr;
}
return objPtr;
}
int main() {
std::vector<std::shared_ptr<Widget>> widgets;
for (unsigned i=0; i < 20; i++) {
std::cout << "Adding widget " << i << std::endl;
widgets.push_back(fastLoadWidget(i));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
while (!widgets.empty()) {
widgets.pop_back();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 0;
}
解决方案
确实,当您std::make_shared
将存储用于新对象和控制块时,它是作为单个块分配的,因此只要存在它就不会释放std::weak_ptr
它。但是,当最后一个std::shared_ptr
对象被销毁时,对象仍然被销毁(它的析构函数运行并且其成员被销毁)。它只是保持分配和未占用的关联存储。
std::vector
为其元素动态分配存储空间。此存储在 外部std::vector
,它不是对象的内存表示的一部分。当你摧毁一个时,Widget
你也摧毁了它的std::vector
成员。该成员的析构函数将释放用于存储其元素的动态分配的内存。唯一不能立即释放的内存是控制块和存储Widget
(应该是sizeof(Widget)
字节)。它不会阻止向量元素的存储立即释放。
推荐阅读
- python - 打字:如何将所有者类绑定到通用描述符?
- google-cloud-platform - GKE 监控,了解 Evictable 和 Non Evictable 内存
- javascript - 如果曾经单击过按钮,则运行一个函数,即使在页面重新加载时也是如此
- python - 如何根据其他事实从不同表中选择列以创建新的数据框python
- javascript - 将数据发送到 MySQL 数据库的 React/Node 错误
- mysql - 如何从触发器mysql中的select中获取值并将其用于IF条件
- flutter - 在 MacOS 中将私有 Flutter 项目存储库从 Github 克隆到 Xcode
- python - 如果键包含特定值(月),则加载对象
- java - 在 JInternalFrame 中使用 JCEF 时,JFrame 中的 JTextField 不可编辑,直到 JFrame 失去焦点
- javascript - JSON.parse() 和 JSON.stringify() 在下面的代码中做什么。我正在建立一个图书馆