#c #string #c 11 #move #swap
#c #строка #c 11 #переместить #поменять местами
Вопрос:
В следующем коде C должно быть три выделения кучи, поскольку в swap()
функции также создается один временный строковый объект. Почему в этом коде только два выделения кучи?
Без использования семантики перемещения
#include <iostream>
#include <unordered_map>
using namespace std;
static uint32_t allocations = 0;
void *operator new(size_t size)
{
allocations ;
cout << "Allocating " << size << " bytesn";
return malloc(size);
}
void swapUsingMove(stringamp; arg1, stringamp; arg2)
{
string temp = arg1;
arg1 = arg2;
arg2 = temp;
cout << allocations << endl;
}
int main()
{
string str1{"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string str2{"ZYXWVUTSRQPONMLKJIHGFEDCBA"};
swapUsingMove(str1, str2);
cout << str1 << " " << str2;
return 0;
}
Вывод
Allocating 51 bytes Allocating 51 bytes 2 ZYXWVUTSRQPONMLKJIHGFEDCBA ABCDEFGHIJKLMNOPQRSTUVWXYZ
С помощью семантики перемещения
#include <iostream>
#include <unordered_map>
using namespace std;
static uint32_t allocations = 0;
void *operator new(size_t size)
{
allocations ;
cout << "Allocating " << size << " bytesn";
return malloc(size);
}
void swapUsingMove(stringamp; arg1, stringamp; arg2)
{
string temp = move(arg1);
arg1 = move(arg2);
arg2 = move(temp);
cout << allocations << endl;
}
int main()
{
string str1{"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string str2{"ZYXWVUTSRQPONMLKJIHGFEDCBA"};
swapUsingMove(str1, str2);
cout << str1 << " " << str2;
return 0;
}
Вывод
Allocating 51 bytes Allocating 51 bytes 2 ZYXWVUTSRQPONMLKJIHGFEDCBA ABCDEFGHIJKLMNOPQRSTUVWXYZ
Даже без использования семантики перемещения, почему существует только два выделения кучи? Где временная строка получает выделенную память? Если в обоих случаях имеется два выделения кучи, то в чем преимущество использования std:: move() здесь?
Комментарии:
1. Не могли бы вы, пожалуйста, показать нам программу, которую вы на самом деле не понимаете («без использования семантики перемещения»)? Также включите фактический результат, который вы получаете от программы, и, возможно, ожидаемый результат.
2. @jtbandes Это не о едином входе, не вводите в заблуждение.
3. какой компилятор вы используете? Для первого я получаю разные выходные данные с помощью gcc и clang (оба с включенной оптимизацией)
4. Вы смотрели на сгенерированный код, чтобы увидеть, что он делает? Возможно, компилятор распознает шаблон «swap» и генерирует код для замены указателей?
5. @ArunSuryan: какую версию GCC и какую командную строку вы используете для компиляции? Я не могу воспроизвести простые тестовые примеры с помощью Godbolt ; Я получаю три распределения (хотя они намного меньше; 27 байт, а не 51).
Ответ №1:
Скорее всего, вы используете реализацию, которая ведет себя в соответствии со стандартом C 98/03 и которая реализует копирование при записи std::string
.
Живая демонстрация: https://godbolt.org/z/rP7M77
Если это так, ваш вопрос не должен быть помечен c 11
, поскольку копирование при записи с тех пор запрещено. (Обычно вместо этого реализуется единый вход, но это другая история.)
Если вы переключитесь на более новый GCC, вы увидите 3 распределения: https://godbolt.org/z/b5q1MM
Комментарии:
1. Итак, в обоих случаях будет три распределения или только в том случае, когда я использую семантику перемещения?
2. @ArunSuryan Не могли бы вы ответить на вопрос из комментариев о том, какая версия GCC? Кроме того, какие флаги компиляции вы используете? В любом случае, похоже, что это некоторая частичная поддержка C 11. COW не разрешен в C 11 и
std::move
не существовал до C 11. Согласно стандартам C , вы не должны иметь возможности использовать и то, и другое.3. это gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
4. @ArunSuryan Почему должно быть 3 выделения с семантикой перемещения? Перемещение просто «крадет» ресурсы, то есть сохраненную строку. Почему он должен что-то выделять?
5. @ArunSuryan И да, похоже, что GCC 4.8.5 смешивает COW и
std::move
features, что не соответствует какому-либо конкретному стандарту C . Я бы посоветовал вам не использовать такую устаревшую версию.