2012-06-13 6 views
4

В настоящее время я управляю жизненным циклом объектов в своем проекте вручную. Я рассматриваю возможность переключения на интеллектуальные указатели, в частности tr1 :: shared_pointer и tr1 :: weak_ptr. Тем не менее, я вижу пару проблем и хотел бы получить некоторый вклад в лучшие практики.Последствия владения моделью с помощью интеллектуальных указателей

Рассмотрим следующую диаграмму классов:

Polyhedron Class Diagram

На этой диаграмме, толстые стрелки представляют ассоциации с семантикой собственности (источник отвечает за удаление цели или цели). Тонкие стрелки представляют ассоциации без права собственности.

Из того, что я понимаю, одним из способов реализации ассоциации с семантикой собственности было бы использовать tr1 :: shared_ptr (или их коллекцию). Другие ассоциации могут быть реализованы с использованием либо tr1 :: shared_ptr, либо tr1 :: weak_ptr. Первый запрещен, если это может привести к циклическим ссылкам, поскольку это предотвратит надлежащее выделение ресурсов.

Как вы можете видеть, существует круг ассоциаций между классами Edge и Side. Я могу легко сломать это, реализуя «левые» и «правильные» ассоциации от Edge to Side, используя tr1 :: weak_ptrs. Тем не менее, я бы предпочел использовать интеллектуальные указатели для документирования в коде семантики собственности ассоциаций. Поэтому я хотел бы использовать shared_ptrs только для ассоциаций, представленных толстыми стрелками на диаграмме, и weak_ptrs для всего остального.

Теперь мой первый вопрос: должен ли я использовать weak_ptrs либерально, как описано выше, или я должен использовать их как можно меньше (только для того, чтобы избежать циклических ссылок)?

Следующий вопрос: Предположим, у меня есть функция, которая вычисляет среднее значение множества вершин. Предположим далее, что я реализовал ассоциацию с многогранника его Вершины так:

class Vertex; 
class Polyhedron { 
protected: 
    std::vector<std::tr1::shared_ptr<Vertex> > m_vertices; 
}; 

и что я реализовал ассоциацию с полутуши ее Вершины так:

class Vertex; 
class Side { 
protected: 
    std::vector<std::tr1::weak_ptr<Vertex> > m_vertices; 
}; 

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

const Vertex centerOfVertices(std::vector<Vertex*> vertices); 

Теперь, если я представляю ассоциации, как указано выше, я вдруг понадобятся две функции, если я все понимаю правильно:

const Vertex centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> > vertices); 
const Vertex centerOfVertices(std::vector<std::tr1::weak_ptr<Vertex> > vertices); 

Потому что я не могу конвертировать между вектором shared_ptr и вектор weak_ptr. Это смешно для меня. Я хотел бы знать, какой подход я должен предпринять здесь, чтобы избежать такой ситуации.

+0

Что вы имеете в виду «а' weak_ptr' не может быть преобразовано в 'shared_ptr'» ? Вызов 'lock()' на 'weak_ptr', и он дает вам' shared' –

+2

. Я думаю, что это будет злоупотреблять 'shared_ptr', я не читал это внимательно, но это не похоже на что-либо на самом деле _shares_. Вместо этого используйте 'unique_ptr' и необработанные указатели и предоставляйте гарантии системам, которые вы даете (слабым) исходным указателям, к тому, что объект, на который они указывают, будет действителен во время их действия. – David

+0

Думаю, я понял бы это намного лучше, если бы знал, что представляет собой «сторона». Это означает «лицо»? – Rook

ответ

1

Однако я бы предпочел использовать интеллектуальные указатели для документирования в коде семантики ассоциаций ассоциаций.

Как и следовало ожидать. В конце концов, это то, что они выражают.

Поэтому я хотел бы использовать shared_ptrs только для ассоциаций, представленных толстыми стрелками на диаграмме, и weak_ptrs для всего остального.

дерзайте, с одной оговоркой: ваша собственность не смотрит на все как общий собственности, это простой, уникальная собственность. Следовательно, соответствующий умный указатель здесь не shared_ptr, а скорее std::unique_ptr, и слабые указатели тогда просто будут грубыми указателями.

Теперь, если я представляю ассоциации, как указано выше, я вдруг понадобятся две функции ...

Да. Ну, или вы используете шаблоны.

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

+0

Спасибо за ваш ответ! –

0

Вы, безусловно, можете использовать shared_ptr для циклических ссылок. Есть редкие ситуации, когда это имеет смысл. Тем не менее, вы должны позаботиться о том, чтобы разбить цикл, как только вы закончите с объектами.

1

Использование общих указателей кажется разумным, особенно если вы обнаружите, что вершины и т. Д. Могут делиться между многогранниками.

Для преобразования вектора слабых указателей на вектор общих указателей, используйте явный конструктор:

centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> >(vertices.begin(), vertices.end())); 
+0

Хорошая идея, спасибо! –

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