2016-05-05 2 views
1

Контекст:Каков правильный способ реализации агрегирования в современном C++?

Это является общим, что возникает ситуация, в которой я требую агрегации: Объект использовать другой объект, не имея его. То есть, некоторый основной модуль будет создавать и совместно использовать объект для/для других.

Однако до сих пор я не нашел правильный способ его реализации.

Предыдущие исследования:

1) C-подобные указатели: Общий объект предоставляется в качестве указателя. Проблема в том, что программист правильно управляет порядком создания, совместного использования и удаления, который может легко переносить оборванные указатели.

int main() 
{ 
    A a; 
    B b(&a); 
    return 0; 
} 

2) Слабые указатели: Использование общий/слабый указатель решить проблему оборванных указателей. Основная проблема заключается в том, что он избегает использования стековых объектов. Он также ретранслирует на исключениях, которые в лучшем случае являются полемикой, в худшем случае просто невозможно (код ядра/низкого уровня).

int main() 
{ 
    std::shared_ptr<A> a(new A()); 
    std::weak_ptr<A> wa = a; // optional, but required to show the weak_ptr use 
    B b(wa); 
} 

3) Общие указатели: Использование только общий указатель имеет ту же проблему, чем (2), но кроме того, владение A неизвестно: что сломать несколько руководящих принципов дизайна.

4) Ссылка на объект: Публикация ссылки на объект решает проблему оборванности и, вероятно, является самым простым решением. С другой стороны, это заставляет агрегированный объект передаваться в конструкторе, он избегает операторов присваивания и вообще ограничивает дизайн.

int main() 
{ 
    A a; 
    B(a); 
} 

5) Никогда не объединяйте, просто передайте в качестве аргумента. Даже если это возможно, это значительно увеличивает количество параметров для некоторых функций. Это, на мой взгляд, слишком большая сложность.

6) Singleton pattern Singleton позволяет получить доступ к одному объекту из нескольких модулей. Но это позволяет только одному экземпляру делиться, и это противоречит нескольким строкам проектирования.

Вопрос:

Что такое правильный способ реализации агрегации в современном C++?

Идеальные цели были бы:

  • сделать легко поддерживать код, и избежать ошибок.
  • Гибкость в использовании по-разному (например, стек/куча)
  • Не слишком много дополнительной сложности или неясного кода.
+3

Не думаю, что здесь достаточно информации, чтобы ответить на вопрос. Это зависит от более архитектурных соображений, чем вы разделили. Все это допустимые варианты в зависимости от других вещей, хотя в «современном» C++ вы предпочитаете не использовать необработанные указатели, если это возможно (а также не нужно использовать «новый» в большинстве случаев) – johnbakers

+2

Нет ни одного True Ответ. Выберите лучший дизайн, чтобы решить вашу конкретную проблему. –

+0

Почему B не принадлежит A? У вас есть пользовательский сборщик мусора, чтобы вернуть кучу? Ожидает ли A? – vegi

ответ

2

Как отметили многие комментаторы, нет ни одного решения вашей проблемы. Однако подобные вещи обсуждались подробно людьми, которые думают о шаблонах проектирования C++ для жизни.Для одной большой дискуссии о лучшей обработке оборванных указателей (включая предложение одного из комментаторов, template <class T> using non_owning_ptr<T> = T*), я предлагаю talk Bjarne Stroustrup на основные правила и рекомендации C++, в частности сегмент, начинающийся с указанной ссылки. В этом отношении также полезен последующий результат Herb Sutter talk, в котором представлены некоторые идеи по инструментам статического анализа для обеспечения соблюдения этих правил.

Я знаю, что это не волшебное решение, которое вы ищете, но для чего это стоит, это, кажется, решение, которое люди путь умнее и путь более опытный с C++, чем я пришел с. Честно говоря, именно по этой причине Бьярне Страуструп провел большую часть своего времени в последнее время по этим правилам и рекомендациям: идеальные решения такого рода вещей не существуют в самом C++, но с некоторыми ограничениями мы можем приблизиться.

1

Мне требуется агрегация: объект использует другой объект без его владения.

Это не какое-либо определение «агрегации», с которым я знаком. Но для целей этого поста я буду использовать его.

Невозможно выразить способность одного объекта обращаться к объекту без его владения в системе типа C++. Существует слишком много способов реализовать эту взаимосвязь для типа, чтобы выразить эту идею.

Предположим, что у нас есть экземпляр A, который имеет доступ к экземпляру B, но не принадлежит B. Итак, как вы определяете взаимосвязь между этими двумя экземплярами? Эта взаимосвязь небезопасна, если B уничтожен, не сообщив сначала. Итак, как мы это гарантируем?

Существует буквально десятки способов. Возможно, B удерживается в shared_ptr, и, таким образом, A может хранить свою ссылку в weak_ptr, тем самым сообщая, когда B больше не существует. Возможно, есть определенный объект C, которому принадлежат как A, так и B, и это обеспечит. Возможно, общая структура кода делает невозможным уничтожение B до A. Возможно, сам B знает, когда он связан с A и будет информировать A в своем деструкторе. Или, может быть, код хрупкий, но каждый человек, написавший код, очень заботится, чтобы убедиться, что A не пережить B.

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

Основы библиотеки v1 включают в себя observer_ptr<T>, который является только оболочкой указателя; он не передает семантику владения. Однако в Рекомендациях Core C++ рекомендуется raw pointers be used for most of these use-without-ownership relations; вместо этого предполагая, что указатели, которые владеют чем-то, должны быть аннотированы owner<T>.

+0

https://en.wikipedia.org/wiki/Object_composition#Aggregation Может быть, мое однострочное описание слишком упрощенное. Если это не определение, с которым вы знакомы, не могли бы вы представить мне свою концепцию агрегирования, пожалуйста? В связи с вопросом, да, есть сотни ситуаций агрегации, поэтому я прошу «правильный» способ. Точно так же ошибки - очень сложная тема, но мы все соглашаемся несколькими способами управлять ими (исключения, возврат ошибки и т. Д.). Я окончательно рассмотрю ваши шаблоны observer_ptr/owner. Спасибо –

+0

@AdrianMaire: «* есть сотни ситуаций агрегации, поэтому я прошу« правильно ». *« Кажется, вы пропустили мою мысль. Потому что есть сотни таких ситуаций, нет * «правильного пути». Не может быть. –

Смежные вопросы