Почему `basic_ios :: swap` делает только частичный обмен? - PullRequest
18 голосов
/ 16 ноября 2011

C ++ 11 §27.5.4.2 / 21:

void swap(basic_ios& rhs);

Эффекты: Состояния *this и rhs должны быть изменены, за исключением того, что rdbuf() должен возвращать то же значение, которое было возвращено до вызова функции, а rhs.rdbuf() должен возвращать то же значение, что и до вызова функции.

Для чего этот частичный обмен полезен?

Может ли это вызвать проблемы?

Ответы [ 2 ]

21 голосов
/ 16 ноября 2011

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

Семантика обмена и перемещения была вмонтирована в нашу систему ввода-вывода спустя десятилетие после ее разработки.И это было не совсем чистое соответствие.

Обратите внимание, что basic_ios::swap является защищенной функцией-членом, и не существует варианта области имен пространства.Таким образом, это может быть вызвано только из производного класса (обычно istream / ostream).Обратите внимание, что i/o_stream::swap также защищен и не имеет варианта области имен.И их задача - вызвать базовый класс swap и затем поменять местами любые локальные данные (например, gcount in istream).

Наконец, на уровне string/filestream вы получите то, что хотели бырассмотрим «нормальный» swap: открытый член и варианты области имен.На этом уровне у вас есть элемент данных string/file buffer (rdbuf) и базовый класс.swap на этом уровне просто меняет базу и члены данных.

Сложная характеристика всего этого заключается в том, что rdbuf() в базовом классе на самом деле является самоссылающимся указателем на производный класс streambuf (basic_filebuf или basic_stringbuf) и , что - это то, почему вы не хотите, чтобы базовый класс менял местами эти самоссылающиеся указатели.

Это делает базу swapстранно, но от этого защищены все, кроме производных клиентов.И код для swap производного клиента впоследствии обманчиво прост.И на производном уровне, swap предается гласности и ведет себя так, как этого ожидают публичные клиенты.

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

Это было весело.Это выглядит странно.Но в конечном итоге это работает.; -)

Небольшая коррекция:

Альберто Ганеш Барбати отвечает за защиту swap на уровне i/ostream.Это был очень хороший вызов с его стороны, который я полностью пропустил с моим первым дизайном.

2 голосов
/ 16 ноября 2011

У меня только один умозрительный ответ ...

Если автор предположил, что поток может использовать внутренний буфер (например, char buffer[50] элемент данных), то это положение необходимо, поскольку очевидно, что содержимое буферов может быть заменено, но их адрес останется неизменным.

Я не знаю, разрешено ли это на самом деле.

...