2008-10-19 2 views
6

В программировании мы сталкиваемся с различными ситуациями, когда мы обязаны использовать промежуточные контейнеры STL, как показано в следующем примере показан:C++ STL: Повторное использование контейнера после очистки?

while(true) 
{ 
    set <int> tempSet; 

    for (int i = 0; i < n; i ++) 
    { 
     if (m.size() == min && m.size() <= max) 
     { 
      tempSet.insert(i); 
     } 
    } 
    //Some condition testing code 
} 

Или

set <int> tempSet; 

while(true) 
{ 
    for (int i = 0; i < n; i ++) 
    { 
     if (m.size() == min && m.size() <= max) 
     { 
      tempSet.insert(i); 
     } 
    } 
    tempSet.clear(); 

    //Some condition testing code 
} 

Какой подход лучше с точки зрения времени и пространства сложность с учетом нынешнего состояния C++-компиляторов?

ответ

2

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

(Space-мудрыми они будут идентичны.)

0

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

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

Всегда предопределять и повторно использовать. Это экономит время и память.

+0

Я не думаю, что вы можете предварительно выделить пространство в наборе. – 2008-10-19 23:24:35

+0

Да, я вижу это. Вы, вероятно, должны были бы сделать что-то глупое с распределителем, чтобы получить приличное предварительное распределение. – EvilTeach 2008-10-19 23:45:08

+0

Я проверил тест. max_size огромен. В этом случае это не проблема. – EvilTeach 2008-10-19 23:56:35

4

Если это вопрос set/map/list, это не будет иметь никакого значения. Если речь идет о vector/hash_set/hash_map/string, вторая будет либо быстрой, либо той же скоростью. Разумеется, эта разница в скорости будет заметна только в том случае, если вы выполняете очень большое количество операций (10 000 целых чисел, введенных в vector, 10 000 раз были примерно в два раза быстрее - 3 секунды и некоторое изменение против 7 секунд.).

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

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

+0

Этот вопрос касается множеств, а не векторов. Также для векторов я обсуждаю вопрос о различии в скорости: предполагается, что векторы растут экспоненциально (обычно дважды каждый раз), поэтому количество распределений амортизируется. – 2008-10-19 23:28:49

+0

Вопрос не относится ни к одному. Если вы потратите время, чтобы фактически запустить некоторые тесты скорости для случая, в котором это имеет значение, вы заметите большой удар производительности. Это не распределение, которое болит, это memcpy после realloc. – hazzen 2008-10-19 23:57:00

+0

@ ChrisJester-Young: Да, количество распределений амортизируется, но лучше `log (n)` allocations, чем `Mlog (n)`. – 2013-02-28 22:35:21

7

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

Оценка производительности не имеет большого значения, но вы должны тем не менее измерить оба случая и сами убедиться.

0

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

15

Первая версия верна. Это проще почти во всех отношениях. Легче писать, читать легче, проще понять, проще в обслуживании и т. Д.

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

Иногда во встроенном программировании полезно избегать помещать вещи в стек; в этом случае вторая версия будет правильной.

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

1

Будет очень мало разницы в производительности между ними. Вы должны принять решение на основе удобочитаемости кода и надежности.

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

1

Вы помещаете свой комплект в стек, поэтому стоимость размещения почти равна нулю!

-1

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

0

Комплект обычно выполнен в виде красного черного дерева. Каждый узел распределяется отдельно, поэтому он не использует преимущества повторного использования. Вот почему оба подхода имеют почти такую ​​же производительность. Вызов «tempSet.clear()» должен занимать примерно то же время, что и разрушение объекта. Первый подход лучше, потому что он имеет одинаковую производительность и соответствует более безопасному стилю программирования.

Вы можете найти общее обсуждение других контейнеров здесь: Reusing a container o creating a new one