Я считаю удобным (и имеющим много кода, который) обертывать некоторый объект хранения в адаптере распределения, и затем этот адаптер распределения обычно используется для определения области гарантированного хранилища в управляющем объекте в течение его времени жизни, которое обычно является временем жизни вызов функции.
Однако здесь, похоже, используется нестандартное расширение VisualStudio, и мне любопытно, что является лучшей парадигмой и почему ..
например большая часть нашего кода все еще использует CString
, Одна из особенностей CString
это возможность заблокировать его содержимое, чтобы вы могли взять неконстантный указатель в базовый буфер и манипулировать им напрямую — функции библиотеки C’la.
Это позволяет очень легко использовать CString
за его автоматическое управление ресурсами, но все же интерфейс с унаследованными библиотеками / кодом, который нуждался в буфере записи Однако блокировка буфера сама по себе не является операцией RAII, поэтому я создал класс RAII для выполнения этой функции (например, снятие блокировки):
// replaces each occurrence of any of the given list of characters with a specified replacement character in-place
inline void ReplaceAll(CStringW & str, const wchar_t * chsOld, const wchar_t chNew)
{
ReplaceAll(make_autobuffer(str), chsOld, chNew);
}
Код, стоящий за make_autobuffer, довольно длинен, но идея сводится к возвращению объекта, который удерживает блокировку в буфере базовой строки, и попросит str освободить эту блокировку буфера при его уничтожении, тем самым освободив буфер для контроля по CString.
Это тривиальная идея, и реализация также довольно тривиальна (множество элементов, которые делают его устойчивым по отношению к широким / узким строкам, и варианты, которые принимают фиксированный размер буфера или нет, и некоторые помощники по отладке и т. Д.).
Но в более общем смысле я часто обнаружил, что очень полезно иметь класс, который принимает неконстантную ссылку на экземпляр чего-либо, и обертки этого экземпляра в некотором виде изменяемого уровня адаптера, а затем освобождает базовую сущность после завершения.
Вопрос в том, есть ли лучший способ сделать это, чем создавать именованную переменную для адаптации:
// replaces each occurrence of any of the given list of characters with a specified replacement character in-place
inline void ReplaceAll(CStringW & str, const wchar_t * chsOld, const wchar_t chNew)
{
auto adapter = make_autobuffer(str);
ReplaceAll(adapter, chsOld, chNew);
}
Это работает, и не нарушает стандарт. Я больше не пытаюсь передать неконстантный объект по ссылке из временного объекта — так как я назвал временный объект менее временным.
Но … это кажется глупым. В конце концов, выполнение вышеизложенного не меняет смысл, насколько я могу судить. И если допуск VisualStudio был нестандартным, то есть ли лучший стандартный способ, который не так глуп?
Но … это кажется глупым. В конце концов, выполнение вышеизложенного не меняет смысл, насколько я могу судить.
Да, это совсем другое. Тем не менее, если бы вы написали
auto const& adapter = make_autobuffer(str);
ReplaceAll(adapter, chsOld, chNew);
это было бы так же, как
ReplaceAll(make_autobuffer(str), chsOld, chNew);
(рассмотрим, что произойдет, если конструктор копирования недоступен для возвращаемого типа make_autobuffer
).
ПРЕДУПРЕЖДЕНИЕ Я просто понял, что мы ничего не знаем о том, что
make_autobuffer
на самом деле возвращается. Позвольте мне высказать мое предположение: я предполагаю, что вы возвращаете класс-оболочку RAII с неявным преобразованием в тип параметра, ожидаемыйReplaceAll
функция (например,char const*
¹)
На «главный вопрос» — это кажется довольно расплывчатым. Я думаю, что вы говорите о нестандартном расширении MSVC к «временным расширениям временных привязок при привязке к неконстантным ссылкам».
Я не понимаю, откуда это в коде, который вы показали, по той простой причине, что вы показываете make_autobuffer
вызывается внутри списка параметров. Таким образом, временное хранилище гарантированно существует до тех пор, пока после того, как этот вызов функции не будет возвращен, нет необходимости связывать / называть вещи для достижения этого. Даже в стандарте C ++ 03.
Если вы хотите расширить блокировку за пределы вызова функции, тогда да, назовите дескриптор RAII.
Аналогичные точки дизайна в стандартной библиотеке (и аналогах Boost):
¹ LPCTSTR в вашем регионе?
В конечном счете, я решил сделать это, чтобы отказаться от использования Wrapper &
в Wrapper
(путем копирования / перемещения).
Передача неконстантной оболочки с помощью ref является явным нарушением правил аргументов C ++. Необходимость объявить это явно раздражала. Передача его по значению означала, что я мог воспользоваться преимуществами правил перемещения Cx11 и не иметь копий для CStringAutoBuffer
(и другие подобные типы временных объектов-оболочек), но все же создайте их на лету, не называя их явно локально.
Это также сохраняет правильность.
В целом, счастливое решение этого жанра вопроса. 🙂