Что такое хороший способ разделить объект между классами? - PullRequest
10 голосов
/ 20 ноября 2011

Каков хороший способ разделить экземпляр объекта между несколькими классами в иерархии классов?У меня следующая ситуация:

class texture_manager;

class world {
    ...
    std::vector<object> objects_;
    skybox skybox_;
}

В настоящее время я реализовал texture_manager как синглтон, и клиенты вызывают его метод экземпляра из любой точки кода.texture_manager должен использоваться object s в векторе objects_, skybox_ и, возможно, другими классами, которые могут быть или не быть частью класса world.Поскольку я пытаюсь ограничить использование синглетонов в моем коде, вы рекомендуете какие-либо альтернативы этому подходу?Одним из решений, которое пришло в голову, было бы передать ссылку texture_manager в качестве аргумента конструкторам всех классов, которым необходим доступ к ней.Благодаря.

1 Ответ

11 голосов
/ 20 ноября 2011

Общий ответ на этот вопрос - использовать ::std::shared_ptr.Или, если у вас этого нет, ::std::tr1::shared_ptr, или если у вас его нет, ::boost::shared_ptr.

В вашем конкретном случае я бы рекомендовал один из нескольких различных подходов:

  1. Одной из возможностей, конечно же, является подход shared_ptr.Вы в основном передаете указатель всем, кому нужен объект, и он автоматически уничтожается, когда никому из них он больше не нужен.Хотя, если ваш менеджер текстур в конечном итоге будет иметь указатели на объекты, указывающие на него, вы создаете ссылочный цикл, и с этим нужно будет обращаться очень осторожно.

  2. ДругойМожно просто объявить ее как локальную переменную в main и передать ее в качестве указателя или ссылки всем, кто в ней нуждается.Он не исчезнет, ​​пока ваша программа не будет завершена таким образом, и вам не придется беспокоиться об управлении временем жизни.Голый указатель или ссылка в этом случае просто хороши.

  3. Третья возможность - это одно из нечетко приемлемых вариантов использования чего-то вроде единственного элемента.И это заслуживает подробного объяснения.

Вы создаете синглтон, единственная работа которого - раздача полезных указателей на вещи.Ключевая особенность, которую он имеет, - это способность сказать, на какую вещь раздавать указатель.Это что-то вроде глобальной настраиваемой фабрики.

Это позволяет вам избежать огромных проблем тестирования, которые вы создаете с помощью синглтона в целом.Просто попросите его разослать указатель на объект-заглушку, когда придет время для проверки.

Это также позволяет вам избежать проблем с контролем доступа / безопасностью (да, они также создают проблемы безопасности), которыесинглтон представляет по той же причине.Вы можете временно попросить его передать указатель на объект, который не разрешает доступ к вещам, к которым раздел кода, который вы собираетесь выполнить, не нуждается в доступе.Эту идею обычно называют принципом наименьшего авторитета.

Основная причина его использования заключается в том, что она избавляет вас от необходимости выяснить, кому нужен ваш указатель, и передать его им.Это также главная причина не использовать его, думая, что через это полезно для вас.Вы также вводите возможность того, что две вещи, которые ожидали получить один и тот же указатель на менеджер текстур, на самом деле получают указатели на другой менеджер текстур из-за потока управления, который вы не ожидали, что в основном является результатом неаккуратного мышления, которое заставило васиспользовать синглтон в первую очередь.Наконец, синглтоны настолько ужасны, что даже их более мягкое использование вызывает у меня зуд.


Лично в вашем случае я бы порекомендовал подход №2, просто создав его в стеке в main и передать указатель туда, где это необходимо.Это заставит вас более тщательно продумывать структуру вашей программы, и этот тип объекта, вероятно, в любом случае должен жить всю жизнь вашей программы.

...