如何管理指向已引用对象内部数据的shared_ptr?

发布于 2024-10-07 20:44:00 字数 1263 浏览 7 评论 0原文

假设我有这些类:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抱着落日 2024-10-14 20:44:00

考虑在 struct Car 中使用 weak_ptr 而不是 shared_ptr,它不会影响引用计数,但可以转换为 shared_ptr< /code> 需要时。

Consider using weak_ptr instead of shared_ptr inside struct Car, it does not contribute to reference count, but can be converted to a shared_ptr when needed.

愿得七秒忆 2024-10-14 20:44:00
void nop(Engine*) { /* do nothing */ }

packed->car.engine = shared_ptr<Engine>(&packed->engine, nop);

说明:这段代码创建了一个shared_ptr,它认为它拥有引擎,但实际上它有一个单独的引用计数器,并且在调用删除器时它不执行任何操作。

void nop(Engine*) { /* do nothing */ }

packed->car.engine = shared_ptr<Engine>(&packed->engine, nop);

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文