Qual é a razão específica pela qual ambos std::sort
e std::ranges::sort
levam ao contexto subjacente de std::string
cópia durante a classificação, enquanto std::swap
apenas trocam os ponteiros no std::string
?
Veja a demonstração com os endereços:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> arr = { "You", "HereIJustWantToHaveMemoryReallocation", "See" };
std::cout << "\nBefore sorting:";
for (auto& s : arr) {
std::cout << "\nString:" << s << " at " << std::addressof(s) << " points to " << (void*)(s.c_str());
}
std::sort(arr.begin(), arr.end());
std::cout << "\nAfter sorting:";
for (auto& s : arr) {
std::cout << "\nString:" << s << " at " << std::addressof(s) << " points to " << (void*)(s.c_str());
}
}
A questão não é como evitar isso, o que pode ser feito facilmente, por exemplo, com std::string_view
. A questão é: por que agir std::sort
e std::ranges::sort
se comportar dessa maneira?
Eu esperaria que o algoritmo de classificação usasse std::swap
algum tipo de semântica de movimento que permitiria std::string
apenas trocar ponteiros para as strings subjacentes, sem tocar nas próprias strings. Por que não é esse o caso?
Com a string longa, ele não usa otimização de string pequena, portanto o ponteiro para os dados da string permanece inalterado. Nesse caso, a troca na verdade apenas move a propriedade entre os dois
std::string
s.Para strings mais curtas, a otimização de strings pequenas é usada e o ponteiro de dados é na verdade um ponteiro dentro do
std::string
próprio objeto. Dessa forma, o ponteiro é exclusivo para cada umstd::string
e não pode ser movido para outrostd::string
.