Вопрос об использовании string :: swap () с временными - PullRequest
5 голосов
/ 13 июля 2010

Следующий сегмент демонстрирует мою проблему: (ошибка компиляции в 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>]

Хотя я понимаю, что str () в stringstream возвращает временное значение, это не имеет смысла, и не сразу было очевидно, что я должен был вызывать подкачку для временного с локальной переменной в качестве параметра вместо моего первого инстинкта. 1007 *

Очевидно, что прямое назначение работает лучше, и более новые стандарты C ++ имеют семантику перемещения, которая идеально подходит, но они недоступны для моей реализации.

Visual Studio не дает этой проблемы из-за того, что он расслаблен в отношении стандарта C ++. Я вроде уже понимаю всю ссылку на const на временную вещь (которая, как я полагаю, является причиной моих ошибок компиляции).

Мой вопрос: Может кто-нибудь объяснить мне, если это единственное решение, и, возможно, объяснить мне, как думать об этом в будущем, чтобы я мог определить и обойти подобные проблемы?

(Если никто не обладает каким-либо отличным пониманием, я, по крайней мере, публикую это здесь для людей с похожими проблемами)

Ответы [ 3 ]

7 голосов
/ 13 июля 2010

Вы не можете привязать временную ссылку к неконстантной ссылке. По этой причине временное значение, возвращаемое из ss.str(), не может быть передано в std::string::swap, который ожидает изменения своего параметра (поэтому он принимает аргумент, используя non-const&).

Вторая версия работает, когда вы вызываете функцию-член для временного объекта, который разрешен.

Но почему вы хотите поменяться в первую очередь? Обычно это просто:

std::string s(ss.str());

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

2 голосов
/ 13 июля 2010

После использования идиомы «своп с временным» достаточно много раз со строками типа

std::vector<int>().swap(v); // clear and minimize capacity

или

std::vector<int>(v).swap(v); // shrink to fit

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

1 голос
/ 13 июля 2010

Причина, по которой вы не можете передать временный аргумент в swap, заключается в том, что аргумент передается по неконстантной ссылке. А временные ссылки могут быть связаны только константными ссылками. Это распространяется на §8.5.3, с соответствующим указанием в пункте 5, второй пункт:

§8.5.3 Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:

  • [маркированный первый, здесь не применяется: привязка к неконстантной ссылке]

  • В противном случае ссылка должна быть на энергонезависимый константный тип (т. Е. Cv1 должен быть константным).

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

§3.10 / 10 lvalue для объекта необходимо для модификации объекта, за исключением того, что rvalue типа class также может использоваться для изменения его референта при определенных обстоятельствах. [Пример: функция-член, вызываемая для объекта (9.3), может модифицировать объект. ]

Строка рассуждений, которую вы запрашиваете в будущем, заключается в том, что, хотя вы можете модифицировать временный объект с помощью его собственных функций, вы не можете передать его функции или методу, который мог бы изменить его (передать по неконстантной ссылке) *

...