Производительность std::vector‹Test› по сравнению с std::vector‹Test*›

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

E.g.:

class Test {
   std::string s;
   Test *other;
};

std::vector<Test> vt;
std::vector<Test*> vpt;

Может ли быть разница в производительности между vt и vpt?

Другими словами: когда я определяю vector<Test>, внутренне компилятор все равно создаст vector<Test*>?


person Pietro    schedule 29.06.2012    source источник


Ответы (2)


Другими словами: когда я определяю вектор, будет ли внутри компилятора создавать вектор в любом случае?

Нет, это не разрешено стандартом C++. Следующий код является допустимым C++:

vector<Test> vt;
Test t1; t1.s = "1"; t1.other = NULL;
Test t2; t2.s = "1"; t2.other = NULL;
vt.push_back(t1);
vt.push_back(t2);
Test* pt = &vt[0];
pt++;
Test q = *pt; // q now equal to Test(2)

Другими словами, вектор «распадается» до массива (доступ к нему, как к массиву C, является законным), поэтому компилятор фактически должен хранить элементы внутри как массив, а не просто хранить указатели.

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

person tbleher    schedule 25.07.2012

В общем, какой бы тип ни хранился в векторе, его экземпляры могут быть скопированы. Это означает, что если вы сохраняете std::string, экземпляры std::string будут скопированы.

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

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

Кроме того, в C++11 перемещение позволяет избежать создания дополнительной копии, если она не нужна.

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


Что касается вашего вопроса о векторе внутреннего указателя, нет, векторы реализованы в виде массивов, размер которых при необходимости периодически изменяется. Вы можете найти реализацию вектора GNU libc++ в Интернете.

Ответ становится намного сложнее на уровне ниже C++. Указатели, конечно, должны быть задействованы, так как вся программа не может поместиться в регистры. Я недостаточно знаю об этом низком уровне, чтобы подробнее остановиться на этом.

person Corbin    schedule 29.06.2012
comment
Это звучит так, как будто использование указателей было быстрее. Я утверждаю, что, по крайней мере, для многих распространенных шаблонов использования дело обстоит противоположно: использование указателей медленнее из-за дополнительной косвенности и накладных расходов на управление памятью. Назначение перемещения C++11 делает это еще более верным, но оно сохраняется даже в C++03. - person Konrad Rudolph; 29.06.2012
comment
Я отредактировал свой вопрос. Может быть, последняя строка проясняет, о чем я блуждаю. - person Pietro; 29.06.2012
comment
@Pietro Обновил мой ответ, чтобы решить эту проблему и, надеюсь, будет очищен. - person Corbin; 29.06.2012
comment
Конрад Рудольф, не могли бы вы объяснить, почему указатель может работать медленнее? если список представляет собой список «Тест», не требуется ли создавать новый экземпляр теста и копировать значение при вызове push_back? Спасибо - person Avihai Marchiano; 26.07.2012