2010-06-17 4 views
4

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

Смотрите этот код ниже:

#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 

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

+5

Здесь есть несколько вариантов дизайна, которые являются спорными, но вот один из них: если вы решили, что хотите связанный список для вставки O (1), не сворачивайте свой собственный - используйте 'std :: список '. –

+2

Когда вы спрашиваете себя, будет ли x быстрее, чем y, попробуйте его измерить. –

ответ

10

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

4

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

-1

Во-первых, рекомендуется использовать указатели Вместо этого, используя собственный класс в векторе. Однако здесь как данные text хранится в виде указателя. Его значение (значение текстового атрибута) не копируется дважды. Таким образом, в этом приложении нет серьезной проблемы с производительностью.

+0

Только если ваш класс большой и дорогой для копирования, и вам нужно сэкономить время. Если ваш класс составляет всего 4 байта, он быстрее и проще хранить по значению. И я думаю, что в этом случае было намерено скопировать содержавшийся текст (хотя его трудно сказать, так как он не предоставил полный конструктор копирования). – Peter

+0

Таким образом, общий сценарий будет использовать указатель вместо этого. –

+0

Размер вряд ли является единственным фактором в решении, поэтому я склонен сказать, что нет, общий сценарий не требует использования интеллектуальных указателей. Использование исходных указателей * определенно * не рекомендуется. –

0

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

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

1

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

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

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

+2

Вот почему существуют умные указатели: чтобы избежать всех этих рисков. – ereOn

+1

Да, это очень помогает. То, что я пытаюсь сказать, я не сторонник использования семантики указателя над семантикой значения во ВСЕХ ВРЕМЯ с указанием производительности. Использование интеллектуальных указателей по-прежнему имеет относительное количество головного мозга по сравнению со значениями. У указателей есть преимущества в производительности, но они также означают общие данные, и вместе с ними есть осложнения, например. в параллелизм. Я верю в KISS (Keep It Sweet & Simple), а преждевременная оптимизация - корень всего зла =) – ryaner

+0

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

3

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

5

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

1

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

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

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

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

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

0

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

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

0

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

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

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