Разница между вектором указателя и вектором значений - PullRequest
0 голосов
/ 08 ноября 2019

Я слышал, что указатели не рекомендуются в C ++, но я не понимаю, почему.

Моя проблема в том, что я хочу создать вектор объектов классов для управления моими классами.

vector<MyClass> vectorOfClass;

Естественно, для лучшей производительности я должен пойти с вектором указателя объектов класса?

vector<MyClass *> vectorOfClass;

Или, возможно, возможно создать вектор ссылки на объекты класса?

vector<MyClass &> vectorOfClass;

Итак, мои вопросы:

  • В чем разница между этими способами?
  • Что наиболее оптимизировано для создания вектора объектов класса?

Ответы [ 5 ]

6 голосов
/ 08 ноября 2019

Или, может быть, возможно создать вектор ссылки на объекты класса?

Нет. Ссылки не являются объектами в C ++. Таким образом, вы не можете создавать массивы ссылок или указатели на ссылки. Однако вы можете использовать std::reference_wrapper, который оборачивает ссылку в объекте.

Что наиболее оптимизировано для создания вектора объектов класса?

Всегда зависит отситуация. Измерить, профилировать и принять решение в соответствии с вашими данными.

В чем разница между этими способами?

Они хранятся по-разному.

Вектор значений в памяти выглядит следующим образом:

+----------------------+
| std::vector<MyClass> |----
+----------------------+   |
                           |
   -------------------------
   |
   v
+-------------+-------------+-------------+-------------+
|   MyClass   |   MyClass   |   MyClass   |   MyClass   |
+-------------+-------------+-------------+-------------+

Тогда как вектор указателя выглядит так:

+-----------------------+
| std::vector<MyClass*> |---
+-----------------------+  |
                           |
          ------------------
          |
          v
       +-------+-------+-------+-------+
       |  ptr  |  ptr  |  ptr  |  ptr  |
       +-------+-------+-------+-------+
           |       |      |          |
           v       |      v          |
+-------------+    | +-------------+ |
|   MyClass   |    | |   MyClass   | |
+-------------+    | +-------------+ |
                   v                 v
        +-------------+         +-------------+
        |   MyClass   |         |   MyClass   |
        +-------------+         +-------------+

Оба имеют свои преимущества и недостатки.

Для значения:

  • Pro: Смежный в памяти. Нет погони за указателем и, как правило, очень быстрая итерация.
  • Pro: Автоматическое управление памятью. Vector будет управлять памятью всех значений, которые он выделяет.
  • Con: Недопустимость ссылки. Изменение размера вектора сделает недействительными все ссылки на объекты внутри него.
  • Con: Менее медленно изменяет размеры с нетривиальными объектами. Изменение размера включает в себя перемещение объектов вокруг. Это может быть медленнее с большими или нетривиальными объектами.

Для указателя:

  • Pro: Нет аннулирования ссылки. Адрес объекта управляется вами.
  • Pro: Более быстрое перераспределение, поскольку это будет стоимость копирования указателей вместо перемещения объектов.
  • Con: Медленная итерация. Для каждого элемента в векторе, CPU должен будет запросить у него память и не может эффективно использовать свой кэш.
  • Con: Вы должны использовать std::unique_ptr для владения памятью, иСкорее всего, выделите каждый объект отчетливо. Выделение большого количества различных объектов выполняется медленно.

Выбор по умолчанию должен быть std::vector<MyClass>. Это, безусловно, самое простое и работает для большинства случаев. Обычно, когда мне нужны ссылки на эти объекты, я обычно использую индекс в векторе, который стабилен, если в середине нет удаленного элемента.

3 голосов
/ 08 ноября 2019

Я слышал, что указатели не рекомендуются в C ++

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

Естественно, для лучшей производительности, я должен пойти с вектором указателя объектов класса?

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

Или, может быть, возможно создать вектор ссылки на объекты класса?

Это невозможно. Тип элемента вектора или любого другого контейнера не может быть ссылкой. Вместо него можно использовать std::reference_wrapper.

В чем разница между этими способами?

vector<MyClass> сохраняет MyClass объектов в векторе. vector<MyClass*> хранит указатели в векторе. vector<MyClass&> нарушает требования вектора и плохо сформирован.

Что наиболее оптимизировано для создания вектора объектов класса?

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

1 голос
/ 08 ноября 2019

Рассмотрите право собственности и позвольте этому руководству принять решение:


Если vector владеет ими, то лучше использовать

vector<MyClass> vectorOfObjects;

или

vector<std::unique_ptr<MyClass>> vectorOfObjects;

Этот последний полезен, если у вас должен быть указатель (на полиморфную основу), но вы все еще хотите, чтобы vector владел объектом.


Если владение находится в другом месте,но вы хотите время от времени менять каждый указатель, а затем использовать

vector<MyClass*> vectorOfObjects;

Но в этом случае вы, возможно, захотите изучить использование интеллектуальных указателей:

vector<shared_ptr<MyClass>> vectorOfObjects;

Наконец, вы не можете использовать vector<MyClass &> vectorOfObjects;, но вы можете использовать std :: reference_wrapper :

vector<std::reference_wrapper<MyClass>> vectorOfObjects;

Опять же, это может быть полезно, только если vector не владеет объектами.


Что касается производительности, каждый раз, когда выделяется память, может быть какая-то стоимость, поэтому использование указателей после создания объектов может помочь, но лучше начать с простого, а затем измерить. vector<MyClass> vectorOfObjects; может быть даже лучше. Ты не узнаешь, пока не измеришь. Это было рассмотрено в этом ответе .

0 голосов
/ 08 ноября 2019

Я слышал, что указатели не рекомендуются в C ++, но я не понимаю, почему.

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

Так, например, скажем, у вас есть параметр функции, который вы хотите изменить ввызывающая функция. В C вы бы использовали указатель:

void func(int* someMumber) {
    *somenumber = 3; // modifies value in caller
}

В C ++ это заменяется передачей по ссылке:

void func(int& someMumber) {
    somenumber = 3; // modifies value in caller
}

Таким образом, нет беспорядочного синтаксиса, чтобы иметь дело си не боятся получить плохой указатель и т. д. Это всегда должно работать, независимо от того, что передает нам вызывающий. ^ 1

Другой пример, скажем, вы хотите динамически распределенные данные:

int* dynamicArray = new int[size];

Когда вы закончите с этим, вам придется запомнить delete это:

delete [] dynamicArray;

Это может запутаться, и тогда вам придется отслеживать, что вы делали и не делали 'т удалить. И затем, если вы что-то не удалите, это приведет к утечке памяти.

C ++ имеет гораздо лучшее решение для этого: std::vector. Затем я могу добавить столько элементов в массив, как только они мне понадобятся:

std::vector<int> dynamicArray;

// later, when I need to store a value
dynamicArray.push_back(someValue);

Не беспокойтесь об утечке данных или о чем-либо подобном. Когда все будет готово, все будет просто освобождено.

Вам нужен указатель в любом случае по какой-то другой причине? Попробуйте умный указатель :

std::unique_ptr<int> ptr = new int;

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

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

Естественно, для лучшей производительности, я должен пойти с вектором указателя объектов класса?

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

Или, возможно, возможно создать вектор ссылки на объекты класса?

Не уверен, что это такЭто возможно, но возможно с std::reference_wrapper.

Итак, мои вопросы:

В чем разница между этими способами?

Что наиболее оптимизировано для создания вектора объектов класса?

Самое большое отличие состоит в том, что если вы передадите адрес локальной переменной в вектор-указатель, и он выйдет изсфера, ваш вектор будет заполнен мусором. Чтобы сделать это правильно, вам нужно будет выделить новый объект. Тогда вам придется удалить его. Это просто намного больше работы.

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

Если вы сохраните егопо значению вам не придется беспокоиться об этом.

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


1: На самом деле, вызывающая сторона не может передать нам литералы, , потому что неконстантныйссылки не могут привязываться к литералам . Но это не относится к делу.

0 голосов
/ 08 ноября 2019

Естественно, для лучшей производительности,

Это не так просто предположить. Наличие вектора указателей означает, что фактические значения могут быть достигнуты только через 2 перенаправления указателя - один для индексации, а другой для доступа к фактическим значениям. Эти указатели могут быть где угодно в памяти. Таким образом, доступ к ним может привести к большому количеству ошибок в кеше. Хорошей идеей будет сохранить объекты как таковые в векторе. Измените эту модель, только если у вас есть достаточные доказательства (= результаты профиля).

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