Рекомендуется ли std:: перемещать строку в контейнеры, которые будут перезаписаны?

У меня есть следующий код

std::vector<std::string> lines;
std::string currentLine;

while(std::getline(std::cin, currentLine)) {
  // // option 1
  // lines.push_back(std::move(currentLine));

  // // option 2
  // lines.push_back(currentLine);
}

Я вижу разные затраты для двух

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

  • Второй подход сделает getline возможным повторное использование буфера и потребует нового распределения буфера для строки в векторе.

В таких ситуациях есть ли "лучший" способ? Может ли компилятор более эффективно оптимизировать тот или иной подход? Или существуют умные реализации строк, которые делают один вариант более реалистичным, чем другой?

Ответ 1

Учитывая преобладание оптимизации коротких строк, я предполагаю, что во многих случаях ничто из этого не будет иметь никакого значения вообще - с SSO, переход заканчивается копированием содержащихся данных в любом случае (даже если источник является rvalue, чтобы он был выбран в качестве источника для перемещения).

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

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

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

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