Временные модифицируемые адаптеры

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

Однако здесь, похоже, используется нестандартное расширение 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 был нестандартным, то есть ли лучший стандартный способ, который не так глуп?

1

Решение

Но … это кажется глупым. В конце концов, выполнение вышеизложенного не меняет смысл, насколько я могу судить.

Да, это совсем другое. Тем не менее, если бы вы написали

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):

  • std :: lock_guard должен быть назван так, чтобы блокировка оставалась за пределами конца полного выражения
  • std :: async возвращает будущее, которое необходимо сохранить в именованной переменной, если вы хотите получить какое-либо подобие фактического асинхронного выполнения (в противном случае деструктор будущего по-прежнему вызывает немедленное блокирование выполнения)

¹ LPCTSTR в вашем регионе?

2

Другие решения

В конечном счете, я решил сделать это, чтобы отказаться от использования Wrapper & в Wrapper (путем копирования / перемещения).

Передача неконстантной оболочки с помощью ref является явным нарушением правил аргументов C ++. Необходимость объявить это явно раздражала. Передача его по значению означала, что я мог воспользоваться преимуществами правил перемещения Cx11 и не иметь копий для CStringAutoBuffer (и другие подобные типы временных объектов-оболочек), но все же создайте их на лету, не называя их явно локально.

Это также сохраняет правильность.

В целом, счастливое решение этого жанра вопроса. 🙂

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector