Как управлять 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;
}
Проблема в том, что этот экземпляр "автомобиля" никогда не будет уничтожен, потому что он имеет счетчик ссылок два. Когда он умрет, у него будет счетчик ссылок навсегда. Знаете ли вы лучший способ продолжать использовать внутренний shared_ptr (чтобы я мог приписать "распакованную" ссылку, если я хочу), и при этом создать эту упакованную структуру?
ОБНОВИТЬ
Я мог бы использовать безоперационное удаление, но тогда было бы очень опасно, если бы я решил сохранить 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 ответа
Рассмотреть возможность использования weak_ptr
вместо shared_ptr
внутри struct Car
, он не влияет на счетчик ссылок, но может быть преобразован в shared_ptr
при необходимости.
void nop(Engine*) { /* do nothing */ }
packed->car.engine = shared_ptr<Engine>(&packed->engine, nop);
Объяснение: Этот код создает shared_ptr, который думает, что ему принадлежит движок, но на самом деле он имеет отдельный счетчик ссылок И ничего не делает, когда вызывается средство удаления.