Что делает CString :: GetBuffer () без параметра размера? - PullRequest
0 голосов
/ 11 сентября 2018

Возможно, я схожу с ума, но я перепробовал все возможные комбинации поиска, и не могу найти определение для CString::GetBuffer() без параметров. Каждая ссылка, которую я ищу, описывает CString::GetBuffer( int ), где переданный параметр int является максимальной длиной буфера. Определение в заголовке для CSimpleStringT::GetBuffer(). Это дало мне следующую ссылку, которая по крайней мере подтверждает существование версии без параметров, но не дает описания ее поведения. https://msdn.microsoft.com/en-us/library/sddk80xf.aspx#csimplestringt__getbuffer

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

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Документация неокончательная.Глядя на доступные здесь источники ATL (https://github.com/dblock/msiext/blob/d8898d0c84965622868b1763958b68e19fd49ba8/externals/WinDDK/7600.16385.1/inc/atl71/atlsimpstr.h - я не претендую на то, что я знаю, официальные они или нет), похоже, что GetBuffer() без аргументов возвращает текущий буфер, клонируя его раньше, если он используется совместно.

С другой стороны, GetBuffer(int) с размером будет проверять (посредством вызова на PrepareWrite и, возможно, PrepareWrite2), если текущий размер буфера больше запрошенного, и если это не так, он будетвыделите новый буфер - таким образом, совпадая с описанием MSDN.

Что касается примечания, PrepareWrite, кажется, становится достаточно изобретательным в том, как он проверяет два условия:

PXSTR PrepareWrite( __in int nLength )
{
    CStringData* pOldData = GetData();
    int nShared = 1-pOldData->nRefs;  // nShared < 0 means true, >= 0 means false
    int nTooShort = pOldData->nAllocLength-nLength;  // nTooShort < 0 means true, >= 0 means false
    if( (nShared|nTooShort) < 0 )  // If either sign bit is set (i.e. either is less than zero), we need to copy data
    {
        PrepareWrite2( nLength );
    }

    return( m_pszData );
}
0 голосов
/ 12 сентября 2018

ТЛ; др

Звоните CString::GetString().


Это задает неправильный вопрос по неправильным причинам. Просто чтобы убрать это с пути, вот ответ из документации :

Возвращаемое значение
PXSTR указатель на (нулевой) символьный буфер объекта.

Это верно для обеих перегрузок, с явным аргументом длины и без него. При вызове перегрузки с использованием аргумента длины внутренний буфер может быть изменен в соответствии с повышенными требованиями к хранилищу перед возвратом указателя на этот буфер.

Начиная с этого комментария становится очевидным, что вопрос заключается в том, чтобы задавать неправильные вопросы. Чтобы понять почему, вам нужно понять, для чего предназначено семейство GetBuffer() членов класса: временно отключить принудительное применение инвариантов CString 1 для модификация , до установления их снова путем вызова одного из ReleaseBuffer () членов. Основным вариантом использования этого является взаимодействие с кодом C (например, Windows API).

Важная информация:

  • GetBuffer() следует вызывать только в том случае, если вы планируете напрямую изменить содержимое сохраненной последовательности символов.
  • Каждый вызов GetBuffer() должен соответствовать вызову ReleaseBuffer() перед использованием любого другого CString члена класса 2 . В частности, обратите внимание, что operator PCXSTR() и деструктор являются членами класса.
  • Пока вы следуете этому протоколу, последовательность контролируемых символов всегда будет заканчиваться нулем.

Учитывая ваш фактический вариант использования (Log.Print("%s\n", myCstring.GetBuffer())), ни один из предыдущих действительно не применим. Поскольку вы не планируете фактически изменять содержимое строки, вы должны получить доступ к неизменяемому интерфейсу CString (например, GetString () или оператор PCXSTR () ). Для этого требуются правильные сигнатуры функций (TCHAR const* против TCHAR*). В противном случае, используйте const_cast, если вы можете быть уверены, что вызываемый не изменит буфер.

В этом есть несколько преимуществ:

  • Это семантически правильно. Если вам нужен только просмотр строки символов, вам не нужен указатель на изменяемый буфер.
  • Лишних копий содержимого нет. CString реализует семантику копирования при записи. Запрос изменяемого буфера требует копирования содержимого для общих экземпляров, даже если вы собираетесь выбросить эту копию сразу после вычисления текущего выражения.
  • Неизменяемый интерфейс не может выйти из строя. Никаких исключений не выдается при вызове operator PXCSTR() или GetString().

1 Соответствующие инварианты: 1 Управляемая последовательность символов всегда заканчивается нулем. 2 GetLength() возвращает количество символов в контролируемой последовательности, исключая нулевой терминатор.

2 Строго необходимо вызывать одну из реализаций ReleaseBuffer(), если содержимое было изменено. Это часто не сразу видно из исходного кода, поэтому всегда вызов ReleaseBuffer() является безопасной опцией.

0 голосов
/ 11 сентября 2018

Хотя документация msdn на самом деле не говорит, что делает GetBuffer без параметра, исходный код MFC показывает ответ:

return( m_pszData );

Так что он просто возвращает указатель на базовый символьный буфер. (Он также проверяет, переданы ли внутренние данные, и сначала их копирует / копирует).

Код находится в atlsimpstr.h

Полная функция:

PXSTR GetBuffer()
{
    CStringData* pData = GetData();
    if( pData->IsShared() )
    {
        Fork( pData->nDataLength );
    }

    return( m_pszData );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...