如何管理指向已引用对象内部数据的shared_ptr?
假设我有这些类:
struct Engine {
int engine_data;
};
struct Car {
shared_ptr<Engine> engine;
int car_data;
};
出于性能原因,我想让它们紧密地打包在内存中(但我不想失去设计的灵活性)。因此,我可以创建一个“打包”结构,以及一个将透明地返回新 B 实例的工厂:
struct PackedCarAndEngine {
Engine engine;
Car car;
};
shared_ptr<Car> new_Car() {
shared_ptr<PackedCarAndEngine> packed = make_shared<PackedCarAndEngine>();
// uses aliasing shared_ptr constructor
packed->car.engine = shared_ptr<Engine>(packed, &packed->engine);
// again
shared_ptr<Car> car = shared_ptr<Car>(packed, &packed->car);
return car;
}
问题是这个“汽车”实例永远不会被销毁,因为它的引用计数为 2。当它死亡时,它的引用计数将永远为一。您是否知道更好的方法来继续使用内部shared_ptr(以便我可以根据需要添加“未打包”引用),并且仍然制作此打包结构?
更新
我可以使用无操作删除器,但是如果我决定保留引擎
而不保留汽车
,那将非常危险:
// ...
packed->car.engine = shared_ptr<Engine>(&packed->engine, do_nothing_deleter);
// ...
shared_ptr<Car> my_car = new_Car();
shared_ptr<Engine> my_engine = my_car->engine;
my_car.reset(); // Danger: engine was destroyed here!!!
cout << my_engine->engine_data; // Crash!
Suppose I have these classes:
struct Engine {
int engine_data;
};
struct Car {
shared_ptr<Engine> engine;
int car_data;
};
For performance reasons, I want to make them tightly packed in memory (but I don't want to lose the flexibility of the design). So, I can create a "packed" structure, and a factory that will transparently return a new B instance:
struct PackedCarAndEngine {
Engine engine;
Car car;
};
shared_ptr<Car> new_Car() {
shared_ptr<PackedCarAndEngine> packed = make_shared<PackedCarAndEngine>();
// uses aliasing shared_ptr constructor
packed->car.engine = shared_ptr<Engine>(packed, &packed->engine);
// again
shared_ptr<Car> car = shared_ptr<Car>(packed, &packed->car);
return car;
}
The problem is that this "car" instance will never be destroyed, because it have a reference count of two. When it dies, it will have a reference count of one, forever. Do you know a better way to keep using the internal shared_ptr's (so that I can attribute an "unpacked" reference if I want), and still make this packed structure?
UPDATE
I could use a no-op deleter, but then it would be very dangerous if I decide to keep the engine
but not the car
:
// ...
packed->car.engine = shared_ptr<Engine>(&packed->engine, do_nothing_deleter);
// ...
shared_ptr<Car> my_car = new_Car();
shared_ptr<Engine> my_engine = my_car->engine;
my_car.reset(); // Danger: engine was destroyed here!!!
cout << my_engine->engine_data; // Crash!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
考虑在
struct Car
中使用weak_ptr
而不是shared_ptr
,它不会影响引用计数,但可以转换为shared_ptr< /code> 需要时。
Consider using
weak_ptr
instead ofshared_ptr
insidestruct Car
, it does not contribute to reference count, but can be converted to ashared_ptr
when needed.说明:这段代码创建了一个shared_ptr,它认为它拥有引擎,但实际上它有一个单独的引用计数器,并且在调用删除器时它不执行任何操作。
Explanation: This code creates a shared_ptr that thinks that it owns the engine but in fact it has a separate reference counter AND it does nothing when the deleter is called.