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

时间:2010-12-14 11:56:26

标签: c++ optimization shared-ptr smart-pointers aliasing

假设我有这些课程:

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;
}

问题是这个“car”实例永远不会被销毁,因为它的引用数为2。当它死亡时,它将具有永久的引用计数。你知道一个更好的方法来继续使用内部的shared_ptr(这样我可以根据需要设置一个“解压缩的”引用),并且仍然使这个打包结构?

更新

我可以使用no-op删除器,但如果我决定保留engine而不是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!

2 个答案:

答案 0 :(得分:1)

考虑在weak_ptr内使用shared_ptr代替struct Car,它不会对参考计数产生影响,但可以在需要时转换为shared_ptr

答案 1 :(得分:0)

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

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

说明:此代码创建一个shared_ptr,认为它拥有引擎,但实际上它有一个单独的引用计数器,并且在调用删除器时它什么都不做。