Следующий сегмент демонстрирует мою проблему: (ошибка компиляции на GCC)
stringstream ss;
string s;
ss << "Hello";
// This fails:
// s.swap(ss.str());
// This works:
ss.str().swap(s);
Моя ошибка:
constSwap.cc:14: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::swap(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
basic_string.tcc:496: note: candidates are: void std::basic_string<_CharT, _Traits, _Alloc>::swap(std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
В то время как я понимаю, что ул. () в stringstream возвращает временный файл, это не имеет смысла и не было сразу очевидно, что я должен был называть подкачку на временном файле с локальной переменной как параметр вместо моего первого инстинкта.
Очевидно прямое присвоение работает лучше, и более новые стандарты C++ имеют семантику перемещения, которая прекрасна, но они не доступны для моей реализации.
Visual Studio не дает эту проблему из-за него ослабляемый о стандарте C++. Я отчасти уже понимаю целую ссылку константы на временную вещь (который я принимаю, причина моих ошибок компиляции).
Мой вопрос: кто-либо может объяснить мне, если это - единственное решение, и, возможно, объясните мне, как думать об этом в будущем, таким образом, я могу определить и работать вокруг подобных проблем?
(Если ни у кого нет большого понимания, я, по крайней мере, отправляю это здесь для людей с подобными проблемами),
После использования идиомы swap-with-temporary достаточное количество раз, со строками типа
std::vector<int>().swap(v); // clear and minimize capacity
или
std::vector<int>(v).swap(v); // shrink to fit
это не кажется таким уж неуместным. Это нормально вызывать swap как функцию-член временного объекта. Конечно, не так идиоматично использовать swap для заполнения строки, построенной по умолчанию, вместо использования конструктора копирования, как уже упоминалось.
Вы не можете привязать временную ссылку к неконстантной ссылке. По этой причине временное значение, возвращенное из ss.str ()
, не может быть передано в std :: string :: swap
, который ожидает изменения своего параметра (для этого он принимает свой аргумент, используя неконстантный &
).
Вторая версия работает, поскольку вы вызываете разрешенную функцию-член временного объекта.
Но почему вы вообще хотите делать свопинг? Обычно достаточно простого:
std::string s(ss.str());
. Это не менее эффективно, чем своп (по крайней мере, в C ++ 0x с семантикой перемещения), но в то же время намного более читабельно.
Причина, по которой вы не можете передать временный аргумент в качестве аргумента swap
, заключается в том, что аргумент передается по неконстантной ссылке. А временные объекты могут быть связаны только константными ссылками. Это распространяется на §8.5.3, с соответствующим указанием в параграфе 5, втором маркере:
§8.5.3 Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:
[первый пункт, здесь не применяется: привязка к неконстантной ссылке]
В противном случае ссылка должна быть на энергонезависимый константный тип (т.е. cv1 должен быть константным).
Причина, по которой запись вызова в обратном направлении работает, заключается в том, что стандарт позволяет вызывать изменяющиеся функции-члены для временных объектов.
§3.10 / 10 Для изменения объекта необходимо lvalue для объекта, за исключением того, что rvalue типа класса также может использоваться для изменения его референта при определенных обстоятельствах. [Пример: функция-член, вызываемая для объекта (9.3), может изменять объект. ]
Логика, которую вы запрашиваете на будущее, заключается в том, что, хотя вы можете изменить временное с помощью его собственных функций, вы не можете передать его функции или методу, которые могли бы его изменить (передать по неконстантной ссылке)