Std::vector: vec.data() или & vec [0]

Когда вы хотите получить доступ к std::vector как массив C, вы можете выбрать по крайней мере четыре разных способа, как вы можете видеть в этом примере:

#include <iostream>
#include <vector>

using namespace std;

int main() {
  std::vector<int> vec;
  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(42);
  vec.push_back(24024);
  {
    int* arr = vec.data();
    cout << arr << endl; /* output: 0x9bca028 */
    cout << arr[3] << endl; /* output : 24024 */
  }
  {
    int* arr = &vec.front();
    cout << arr << endl; /* output: 0x9bca028 */
    cout << arr[3] << endl; /* output : 24024 */
  }
  {
    int* arr = &vec[0];
    cout << arr << endl; /* output: 0x9bca028 */
    cout << arr[3] << endl; /* output : 24024 */
  }
  {
    int* arr = &vec.at(0);
    cout << arr << endl; /* output: 0x9bca028 */
    cout << arr[3] << endl; /* output : 24024 */
  }
}

В большинстве случаев я нашел &vec[0]. Я думаю, что он наименее изящный, поэтому... почему он наиболее часто используется? Является ли более эффективным или более совместимым? Я не могу найти много документации о data().

Ответы

Ответ 1

data() является совершенно новым для С++ 11, поэтому вы не видите его так часто. Идея использования &vec.front() мне даже и не приходила в голову, вероятно, потому, что я использую operator[] чаще, чем front() (почти никогда). Я думаю, это то же самое для других людей.

Ответ 2

Если вы используете С++ 11, то использовать data() определенно предпочтительнее. В частности, если вектор пуст, то использование любого из двух других вариантов дает поведение undefined! Если вы не используете С++ 11, и вектор может быть пустым, тогда обязательно проверьте это условие.

Ответ 3

Использование & vec [0] является наиболее распространенным, хотя, я согласен, выглядит немного странно. Одно нужно помнить о будущем. Если ваш вектор является вектором объектов, класс которых перегружает оператор &(), поймите, что это вызовет странное поведение, если вы вызываете & vec [0].

Это не получит начальный адрес первого элемента во внутреннем смежном массиве объектов, он вернет все, что вернет vec [0].operator &(). Большинство, если не все время, это не адрес, который вы ищете (ручная волна джедая).

Хорошим примером этого является ATL CComPtr. Он перегружает оператор &(), поэтому сохранение его в векторе может быть проблематичным. Чтобы обойти это, ATL имеет класс шаблонов CAdapt, который может быть использован для скрытия оператора &() на CComPtr

Ответ 4

До С++ 11 std::array Я бы сказал, что std::vector был наиболее распространенным контейнером, который будет использоваться вместо массива C-стиля. Оператор [] обычно подразумевает постоянный доступ времени (это то, о чем говорит std::vector), и поэтому большинство кодеров обычно выбирают этот стиль, чтобы отображать доступ и поведение, подобные массиву.

Ответ 5

data() уже некоторое время является частью std::string, поэтому вы можете прочитать об этом. Я обнаружил, что реализация data() в std::vector аналогична. Я иногда использую data() для обработки std::string как массив необработанных байтов.