Как управлять shared_ptr, который указывает на внутренние данные уже упомянутого объекта? - PullRequest
3 голосов
/ 14 декабря 2010

Предположим, у меня есть эти классы:

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

Проблема в том, что этот экземпляр "автомобиля" никогда не будет уничтожен, поскольку он имеет счетчик ссылок, равный двум. Когда он умрет, у него будет счетчик ссылок навсегда. Знаете ли вы лучший способ продолжать использовать внутренний shared_ptr (чтобы я мог приписать «распакованную» ссылку, если я хочу), и при этом создать эту упакованную структуру?

UPDATE

Я мог бы использовать безоперационное средство удаления, но тогда было бы очень опасно, если бы я решил оставить 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 ]

1 голос
/ 14 декабря 2010

Попробуйте использовать weak_ptr вместо shared_ptr внутри struct Car, это не влияет на счетчик ссылок, но при необходимости может быть преобразовано в shared_ptr.

0 голосов
/ 14 декабря 2010
void nop(Engine*) { /* do nothing */ }

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

Объяснение: Этот код создает shared_ptr, который считает, что ему принадлежит движок, но на самом деле он имеет отдельный счетчик ссылок И ничего не делает при вызове средства удаления.

...