Когда необязательно перераспределять параметр `[in, out]`?

Если у меня есть параметр [in,out] BSTR*, и я хочу изменить содержимое строки, но при этом сохранить ту же длину, могу ли я просто использовать его повторно или мне нужно перераспределить / освободить и выделить BSTR?

MSDN говорит:

Для параметров [in, out] вызывающий объект выделяет память, метод или свойство могут необязательно освобождать и перераспределять ее, а вызывающая сторона, наконец, отвечает за удаление памяти.

Чтобы быть более полным, когда это необязательно?


person Afriza N. Arief    schedule 06.06.2013    source источник


Ответы (1)


когда это необязательно

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

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

Строковый параметр ввода / вывода будет выглядеть так. При первом выполнении он увеличивает первый символ входного значения без перераспределения, затем он заменит значение новым:

STDMETHOD(Method)(/* [in, out] */ BSTR* psValue) throw()
{
    if(!psValue)
        return E_POINTER;
    static INT g_nCounter = 0;
    if(++g_nCounter > 1)
    {
        // Deallocate old, Allocate new
        SysFreeString(*psValue);
        *psValue = SysAllocString(L"New Value");
    } else
    {
        // No Re-allocation
        if(SysStringLen(*psValue) > 0)
            (*psValue)[0]++;
    }
    return S_OK;
}

Код на основе ATL может выглядеть немного лучше:

STDMETHOD(Method)(BSTR* psValue) throw()
{
    _ATLTRY
    {
        ATLENSURE_THROW(psValue, E_POINTER);
        CComBSTR& sValue = reinterpret_cast<CComBSTR&>(*psValue);
        static INT g_nCounter = 0;
        if(++g_nCounter > 1)
        {
            sValue = _T("New Value");
        } else
        {
            if(sValue.Length() > 1)
                sValue[0]++;
        }
    }
    _ATLCATCH(Exception)
    {
        return Exception;
    }
    return S_OK;
}

Код вызывающей стороны может быть таким:

CComBSTR sValue = _T("Old Value");
Method(&sValue);
CComBSTR sValueA = sValue; // Gets you "Pld Value"
Method(&sValue);
CComBSTR sValueB = sValue; // Gets you "New Value"
person Roman R.    schedule 06.06.2013
comment
Вы хотите прокомментировать тему BSTR в качестве примера? - person Afriza N. Arief; 07.06.2013
comment
Мои глаза продолжают смотреть на CComBSTR& sValue = reinterpret_cast<CComBSTR&>(*psValue);. CComBSTR деструктор не будет вызываться в конце области видимости? А если бы я вызвал Method() с необработанной переменной BSTR, reinterpret_cast не причинит никакого вреда? - person Afriza N. Arief; 07.06.2013
comment
Деструктор, конечно, НЕ будет вызываться (конструктор тоже не вызывается). Это дает вам возможность рассматривать необработанную переменную BSTR как собственный класс, потому что CComBSTR - это тонкая оболочка. Для вызывающей стороны не имеет значения, является ли это BSTR, CComBSTR или даже совместимая переменная из другой среды, такой как VB. - person Roman R.; 07.06.2013