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

Здравствуйте, WhatsApp API все еще находится в бета-версии на сегодняшний день (апрель 2019 года), и вам нужно подождать, пока команда WhatsApp подтвердит ваш доступ к API. Если вы хотите интегрироваться с WhatsApp, вы все равно можете обратиться к некоторым провайдерам, которые получили ранний доступ, таким как Twilio: https://www.twilio.com/whatsapp

7
задан Tim Cooper 16 March 2009 в 02:45
поделиться

7 ответов

STL действительно имеет тенденцию вызывать этот вид вещи. Спецификация не позволяет memcpy'ing, потому что это не работает во всех случаях. Существует документ, описывающий EASTL, набор изменений, сделанных EA сделать это более подходящим в их целях, который действительно имеет метод объявления, что тип безопасен к memcpy. К сожалению, это не AFAIK с открытым исходным кодом, таким образом, мы не можем играть с ним.

IIRC Dinkumware STL (тот в VS) выращивает векторы к 50% каждый раз.

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

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

6
ответ дан 6 December 2019 в 07:52
поделиться

Не забывайте считать вызовы конструктора копии необходимыми к push_back временный файл C объект в вектор. Каждое повторение будет звонить Cскопируйте конструктора, по крайней мере, однажды.

Если Вы добавляете больше кода печати, немного более ясно, что продолжается:

std::vector<C> A;
std::vector<C>::size_type prevCapacity = A.capacity();

for (int i=0; i < 50; i++) {
    A.push_back(i);
    if(prevCapacity != A.capacity()) {
       cout << "capacity " << prevCapacity << " -> " << A.capacity() << "\n";
    }
    prevCapacity = A.capacity();
}

Это имеет следующий вывод:

capacity 0 -> 1
capacity 1 -> 2
capacity 2 -> 3
capacity 3 -> 4
capacity 4 -> 6
capacity 6 -> 9
capacity 9 -> 13
capacity 13 -> 19
capacity 19 -> 28
capacity 28 -> 42
capacity 42 -> 63

Таким образом да, полные увеличения к 50% каждый раз, и это составляет 127 из копий:

1 + 2 + 3 + 4 + 6 + 9 + 13 + 19 + 28 + 42 = 127

Добавьте 50 дополнительных копий от 50 вызовов до push_back и Вы имеете 177:

127 + 50 = 177
8
ответ дан 6 December 2019 в 07:52
поделиться

Если я вспоминаю правильно, C++ 0x может иметь семантику перемещения (кроме того, для копирования семантики), однако, можно реализовать более эффективного конструктора копии, если Вы действительно хотите.

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

1
ответ дан 6 December 2019 в 07:52
поделиться

Похоже, что дополнения к C++ 0x помогут здесь; посмотрите обновления STL и Rvalue.

1
ответ дан 6 December 2019 в 07:52
поделиться

Мой вопрос:

(a) почему конструктора копии вызывают так часто?

Поскольку, когда вектор изменен, необходимо скопировать все элементы со старого буфера в новый буфер. Это вызвано тем, что вектор гарантирует, что объекты хранятся в последовательных ячейках памяти.

(b) там какой-либо путь состоит в том, чтобы избегать использования конструктора копии, если Вы просто перемещаете объект от одного местоположения до другого?

Нет нет никакого способа избежать использования конструктора копии.
Это, потому что объект имеет несколько участников, которые должны быть инициализированы правильно.
При использовании memcpy, как делают Вы знаете, что объект был инициализирован правильно для объекта!

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

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

Удвоение каждый раз должно вызвать конструктора копии 64 раза. Если бы Вы были очень соответствующими о поддержании на низком уровне использования памяти, то, увеличиваясь на 50% каждый раз должен вызвать конструктора копии 121 раз. Таким образом, где эти 177 прибывают из?

Вектор выделил размер = 1:
Добавьте элемент 1: (никакое перераспределение), Но элемент копий 1 в вектор.
Добавьте элемент 2: Перераспределите буфер (размер 2): элемент Копии 1 через. Элемент копии 2 в вектор.
Добавьте элемент 3: Перераспределите буфер (размер 4): элемент Копии 1-2 через. Элемент копии 3 в вектор.
Добавьте элемент 4: элемент Копии 4 в вектор
Добавьте элемент 5: Перераспределите буфер (размер 8): элемент Копии 1-4 через. Элемент копии 5 в вектор.
Добавьте элемент 6: элемент Копии 6 в вектор
Добавьте элемент 7: элемент Копии 7 в вектор
Добавьте элемент 8: элемент Копии 8 в вектор
Добавьте элемент 9: Перераспределите буфер (размер 16): элемент Копии 1-8 через. Элемент копии 9 в вектор.
Добавьте элемент 10: элемент Копии 10 в вектор
и т.д.

Сначала 10 элементов взяли 25 конструкций копии.
При использовании резерва сначала, только потребовалось бы 10 конструкций копии.

7
ответ дан 6 December 2019 в 07:52
поделиться

Обойти эту проблему, почему бы не использовать вектор указателей вместо вектора объектов? Затем delete каждый элемент при разрушении вектора.

Другими словами, std::vector<C*> вместо std::vector<C>. Указатели Memcpy'ing очень быстры.

0
ответ дан 6 December 2019 в 07:52
поделиться

Просто примечание, остерегаться добавляющих указателей на вектор как способ минимизировать копирование затрат, с тех пор

  1. Местность неправильных данных указателей в векторе делает неуказательную версию с последовательными объектами выполненными кругами вокруг версии указателя, когда вектор на самом деле используется.
  2. Выделение "кучи" медленнее, чем выделение стека.

Вы чаще используете вектор или добавляете материал к нему?

0
ответ дан 6 December 2019 в 07:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: