Композиция в C ++ с сырым или умным указателем? - PullRequest
7 голосов
/ 11 декабря 2010

Небольшой пример того, что я хочу сделать.

У меня есть список (выделенных в стек) вершин

class Vertex {

    int id;
    double x;
    double y;
    double z;
};

и хотите создать список ребер

class Edge {

    int id;
    Vertex * source;
    Vertex * target;
};

с двумя указателями на его исходную и целевую вершины.

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

Итак, мой вопрос: есть ли интеллектуальный указатель, который был бы здесь полезен, или мне просто использовать обычный указатель, как указано выше?

Редактировать

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

Во-первых, список должен иметь вершины, поэтому они находятся в стеке.

Во-вторых, идентификаторы для другой программы.

Требуется файл со списком всех вершин и их координат, а также со списком всех ребер и идентификаторов двух его вершин.

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

(помимо прочего, выполняются какие-то надрезы и нарезки)

Ответы [ 5 ]

7 голосов
/ 11 декабря 2010

Что такое композиция


Композиция (в терминах UML) - это ассоциация, когда данный объект является «частью» других объектов, то есть имеет одинаковое время жизни и, что является наиболее важным и характерным, не существует / имеет смысл сам по себе .

Согласно этому описанию, состав - это не то, чего мы хотим достичь - см. Вторую часть.

В C или C ++ лучший способ реализовать композицию без использования указателей:

class Edge {

    int id;
    Vertex source;
    Vertex target;
};

Этот подход является наилучшим с точки зрения использования памяти (один блок памяти для всего объекта вместе с составными объектами) и, вероятно, также эффективности. Когда вам нужен состав - переходите к этому решению.

Почему композиция не подходит для этой проблемы


Композиция подразумевает некоторые последствия:

  • Составленные объекты не существуют сами по себе,
  • Их связь с составным объектом постоянна в течение всего срока службы этого объекта.

В вашей модели данных у вас есть отдельное значение:

  • Массив вершин (независимый),
  • Массив ребер.

Возможно, оба размещены в стеке (но это не очень важно).

Тогда вы хотите, чтобы каждое ребро относилось к N вершинам.

Край НЕ владеет ими - он только относится к ним. Таким образом, ни композиция, ни интеллектуальный указатель (который предназначен для введения какой-либо ассоциации владения) здесь не то, что вам нужно, потому что дизайн говорит, что вершины принадлежат массиву вершин, а не ребрам .

Так что идите за простым указателем.

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

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

Используйте обычный указатель. Если нацеленные объекты расположены в стеке, интеллектуальный указатель не будет таким уж полезным.

Если вас больше интересует проверка безопасности и границ и так далее, закажите каждый Vertex по его идентификатору (например, выберите 0<=id<n, тогда у вас может быть массив размером n), храните идентификаторы в Edge, а не в указателях. Затем вы можете использовать assert или что-то еще, чтобы проверить, что идентификаторы находятся в допустимом диапазоне.

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

Вообще говоря, умные указатели являются «умными», потому что они имеют дело с собственностью .В вышесказанном, кому вы хотите владеть вершинами?

0 голосов
/ 11 декабря 2010

Это обычный компромисс: умный указатель будет безопаснее, но медленнее. Используйте Boost's shared_ptr, если вы хотите пойти по этому пути.

Для «бизнес-логики» я бы настоятельно рекомендовал использовать умные указатели. Но, похоже, вы выполняете интенсивную обработку графического процессора, что является одним из случаев, когда скорость может быть важным фактором. Поэтому я предлагаю:

//typedef Vertex *VertexPtr
typedef shared_ptr<Vertex> VertexPtr

class Edge {
    int id;
    VertexPtr source;
    VertexPtr target;
};

Используйте это для отладки и переключайте //, когда все работает для повышения скорости.

ПРИМЕЧАНИЕ. Если существует вероятность того, что вершина может указывать на ребро, которое указывает на нее, все становится сложнее - вам нужно будет использовать weak_ptr для одного из указателей, чтобы избежать циклических ссылок.

0 голосов
/ 11 декабря 2010

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

...