Вектор производительности STL - PullRequest
4 голосов
/ 17 июня 2010

Класс вектор STL хранит копию объекта, используя конструктор копирования каждый раз, когда я вызываю push_back.Разве это не замедлит программу?Я могу иметь собственный класс связанного списка, который имеет дело с указателями на объекты.Хотя это не будет иметь некоторые преимущества STL, но все же должно быть быстрее.

См. Этот код ниже:

#include <vector>
#include <iostream>  
#include <cstring>

using namespace std;

class myclass
{
    public:
        char* text;

        myclass(const char* val)
        {
           text = new char[10]; 
           strcpy(text, val);
        }

        myclass(const myclass& v)
        {
            cout << "copy\n";
            //copy data
        }
};

int main()
{
    vector<myclass> list;
    myclass m1("first");
    myclass m2("second");

    cout << "adding first...";
    list.push_back(m1);

    cout << "adding second...";
    list.push_back(m2);

    cout << "returning...";
    myclass& ret1 = list.at(0);
    cout << ret1.text << endl;

    return 0;
}

его вывод выглядит как:

adding first...copy
adding second...copy
copy

В выводе показано, что конструктор копирования вызывается оба раза при добавлении и получениизначение даже тогда.Влияет ли это на производительность, особенно если у нас большие объекты?

Ответы [ 11 ]

10 голосов
/ 17 июня 2010

Копирование повлияет на производительность. Если вы храните большие объекты в стандартных контейнерах, было бы неплохо использовать умные указатели вместо самих объектов.

5 голосов
/ 17 июня 2010

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

4 голосов
/ 17 июня 2010

Да, это так. Это одна из главных причин, по которой мы будем получать ссылки на rvalue в C ++ 0x.

3 голосов
/ 17 июня 2010

Если вы не храните основные типы, рекомендуется использовать указатели в качестве векторных элементов вместо самих реальных объектов. И во многих случаях лучше использовать умные указатели.
Копия ctor все равно будет вызываться - не класса, а класса интеллектуальных указателей.

1 голос
/ 17 июня 2010

Вы можете не верить этому, но vector (а еще лучше deque) - самые быстрые контейнеры, которые STL может предложить для большинства задач.

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

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

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

И если на самом деле ваш класс огромен или запрещен для копирования, всегда есть boost::ptr_vector, хотя, если вы не используете пул, вы явно выбрасываете локальность кэша у окна;)

1 голос
/ 17 июня 2010

На ноте C ++ 0x std :: vector и friends получит emplace_back (), который поместит элемент на место до конца вектора.

http://msdn.microsoft.com/en-us/library/dd647620.aspx

1 голос
/ 17 июня 2010

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

ТОЛЬКО если вы обнаружите, что производительности недостаточно, если вы рассмотрите возможность использования указателей, а затем внимательно отнеситесь к управлению памятью.

Иесли вам нужны указатели, просто используйте vector<myclass*> вместо того, чтобы развертывать свой собственный класс коллекции.В этом вся прелесть того, что STL является родовым =)

0 голосов
/ 17 июня 2010

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

Если вместо этого вы используете deque, товам гарантированно вставляется постоянное время сзади (или спереди) контейнера, сохраняя при этом полезные функции, такие как произвольный доступ.

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

0 голосов
/ 17 июня 2010

Копирование объектов может иметь непредвиденные побочные эффекты. Реальность такова, что классы C ++ часто не пишутся для копирования, и поэтому это может привести к ошибкам ... идеалист будет утверждать, что «они должны писать свои классы правильно», но я предпочитаю иметь дело с реальностью, это даже не будет так редко случается. Не говоря уже о том, что запись вашего класса о создании / уничтожении будет происходить очень часто.

По сути дело не в том, что кодер имел в виду , а в том, что сделана копия. Это само по себе означает, что это плохой план для нетривиальных типов. Для простых случаев это хорошо (скажем, класс Point2D), но будьте осторожны и в целом, если класс не переносит небольшое количество данных, храните указатели (или используйте умные указатели).

0 голосов
/ 17 июня 2010

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

Также обратите внимание, что я не верю, что возвращение на самом деле делает копию. То, что вы видите, это то, что «добавление второго», вероятно, делает две копии: во-первых, он должен расширить вектор с 1 до (вероятно) 2, и скопировать старый элемент из его предыдущего местоположения в новое, затем скопировать элемент 2 на свое место.

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