2014-11-19 1 views
1

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

Это, кажется, использует нестандартное расширение VisualStudio, однако, и мне любопытно, как к тому, что лучше парадигма и почему ..

например в нашем коде все еще используется CString. Одной из особенностей CString является возможность блокировки его содержимого, чтобы вы могли не указать указатель в базовый буфер и манипулировать им напрямую - функции библиотеки a'la C.

Это делает его очень простым в использовании 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); 
} 

Это работает, и не нарушает стандарт. Я больше не пытаюсь передать объект non-const по ref из временного объекта - поскольку я заставил временный объект быть менее временным, назвав его.

Но ... это кажется глупым. В конце дня выполнение вышеизложенного не меняет значения, насколько я могу судить. И если надбавка VisualStudio была нестандартной, то есть ли лучший стандартный способ, который не настолько глупый?

ответ

0

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

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

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

В целом, счастливое решение для этого жанра проблемы. :)

2

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

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

auto const& adapter = make_autobuffer(str); 
ReplaceAll(adapter, chsOld, chNew); 

, который был бы таким же, как

ReplaceAll(make_autobuffer(str), chsOld, chNew); 

(что произойдет, если конструктор копирования не доступен для типа возвращаемого make_autobuffer).

ВНИМАНИЕ Я просто понял, что мы ничего не знаем о том, что на самом деле make_autobuffer возвращается. Позвольте мне высказать свое предположение: я предполагаю, что вы возвращаете класс RAII обертку с неявным преобразованием к типу параметра ожидаемой функцией ReplaceAll (например char const* ¹)


Onto «основной вопрос» - это, кажется, довольно расплывчатый. Я думаю, вы говорите о нестандартном расширении MSVC к «временным расширениям временных рядов при привязке к неконстантным ссылкам».

Я не вижу, где это входит в код, который вы показали, по той простой причине, что вы вызываете внутри списка параметров make_autobuffer. Таким образом, временное гарантируется, что оно будет существовать до тех пор, пока вызов функции не вернется в любом случае, нет необходимости связывать/называть вещи для достижения этого. Даже в стандартном C++ 03.

Если вы хотите расширить блокировку до вызова функции, тогда да, назовите ручку RAII.


Похожих дизайн точек в стандартной библиотеке (и увеличить аналоги):

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

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

+0

sehe - спасибо, что нашли время ответить. Я думаю, что мое дело похоже на std :: lock_guard. Я не нуждаюсь в нем после выполнения инструкции, поэтому удобен для not-name-it. Да, make_autobuffer возвращает автобуфер, который имеет 'operator const TCHAR *'. D'oh Я думаю, что вижу проблему: make_autobuffer возвращает неназванный экземпляр autobuffer, который должен иметь перемещение ctor/operator, добавленное к нему (он имеет только неконстантную копию ctor). Еще раз спасибо. – Mordachai