QueryInterface brasketing
От: grad  
Дата: 04.07.02 13:13
Оценка:
Пример из Д.Бокса
STDMETHODIMP GorillaClass::CreateInstance(IUnknown *pUnkOuter,
                                      REFIID riid,
                      void** ppv)
{
  *ppv = 0;
  
  if(pUnkOuter !=0)
      return CLASS_E_NOAGGREGATION;

  Gorilla* p = new Gorilla;
  
  if(p == 0)
      return E_OUTOFMEMORY;

  p->AddRef();

  HRESULT hr = p->QueryInterface(riid, ppv);

  p->Release();

  return hr;
}
утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release
вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни.
Может ли кто-нибудь из присутствующих господ меня разубедить?
Re: QueryInterface brasketing
От: Аноним  
Дата: 04.07.02 13:56
Оценка:
Здравствуйте grad, Вы писали:

G>Пример из Д.Бокса

G>
G>STDMETHODIMP GorillaClass::CreateInstance(IUnknown *pUnkOuter,
G>                                      REFIID riid,
G>                      void** ppv)
G>{
G>  *ppv = 0;
G>  
G>  if(pUnkOuter !=0)
G>      return CLASS_E_NOAGGREGATION;

G>  Gorilla* p = new Gorilla;
G>  
G>  if(p == 0)
G>      return E_OUTOFMEMORY;

G>  p->AddRef();

G>  HRESULT hr = p->QueryInterface(riid, ppv);

G>  p->Release();

G>  return hr;
G>}
G>
утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release

G>вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни.
G>Может ли кто-нибудь из присутствующих господ меня разубедить?

Я могу ошибаться, но возможно это сделано для автоматического удаления объекта, в случае если QueryInterface не пройдет.
После вызова new класс создается с нулевым счетчиком ссылок. AddRef увеличивает счетчик ссылок. Если QueryInterface не прошел, последующий Release обнулит счетчик ссылок и объект удалиться.
Re: QueryInterface brasketing
От: Sergey Россия  
Дата: 04.07.02 14:15
Оценка: 3 (1)
Здравствуйте grad, Вы писали:

G>Пример из Д.Бокса

G>
G>STDMETHODIMP GorillaClass::CreateInstance(IUnknown *pUnkOuter,
G>                                      REFIID riid,
G>                      void** ppv)
G>{
G>  *ppv = 0;
G>  
G>  if(pUnkOuter !=0)
G>      return CLASS_E_NOAGGREGATION;

G>  Gorilla* p = new Gorilla;
G>  
G>  if(p == 0)
G>      return E_OUTOFMEMORY;

G>  p->AddRef();

G>  HRESULT hr = p->QueryInterface(riid, ppv);

G>  p->Release();

G>  return hr;
G>}
G>
утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release

G>вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни.
G>Может ли кто-нибудь из присутствующих господ меня разубедить?

Чтоб объект уничтожился, если QueryInterface вернет плохой hr.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: QueryInterface brasketing
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.07.02 18:48
Оценка:
Здравствуйте grad, Вы писали:


  Gorilla* p = new Gorilla; // RefCnt == 0 (обычно)
  
  if(p == 0)
      return E_OUTOFMEMORY;

  p->AddRef(); // RefCnt == 1

  HRESULT hr = p->QueryInterface(riid, ppv); 
  // RefCnt == 2 (если успех) и 1 если неудача.


  p->Release();
  // RefCnt == 1 (если успех) и 0 если неудача.
  // Естественно, что при нуле объект сомоуничтожится



В общем — это не более чем выпендреж писателя.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: QueryInterface brasketing
От: grad  
Дата: 05.07.02 06:46
Оценка:
Кажется понял. Если обобщить
p->AddRef(); 
Function(p);\\любая ф-ция, которая может потенциально оставить внешнюю ссылку на p 
p->Release();
прием, который помогает избавиться от опасного delete p.
Re[3]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 05.07.02 10:32
Оценка:
Здравствуйте grad, Вы писали:

G>Кажется понял. Если обобщить

G>
p->>AddRef(); 
G>Function(p);\\любая ф-ция, которая может потенциально оставить внешнюю ссылку на p 
p->>Release();
G>
прием, который помогает избавиться от опасного delete p.


Ну не такой он и опасный. Автор вполне мог написать:
HRESULT hr = p->QueryInterface(riid, ppv); 
if (FAILED(hr)) delete p;

но почему-то не написал
Re[4]: QueryInterface brasketing
От: grad  
Дата: 05.07.02 10:46
Оценка:
А вот что еще в голову пришло.
Если применять подсчет ссылок — delete вызывает экземпляр.
Если применять FAILED — delete вызывает объект класса.
New — все время вызывает объект класса.
Если случится так что классы фабрики и экземпляра используют разные кучи — не может ли это привести к ошибке?
Re[3]: QueryInterface brasketing
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.07.02 17:42
Оценка:
Здравствуйте grad, Вы писали:

G>Кажется понял. Если обобщить

G>
p->>AddRef(); 
G>Function(p);\\любая ф-ция, которая может потенциально оставить внешнюю ссылку на p 
p->>Release();
G>
прием, который помогает избавиться от опасного delete p.


delete-ов сдесь вообще нет. Это просто еще один способ вскипятить чайник.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 08.07.02 02:51
Оценка:
Здравствуйте VladD2, Вы писали:

[skipped]

VD>delete-ов сдесь вообще нет. Это просто еще один способ вскипятить чайник.


но Release()-то
delete this;
вызывает!
Re[5]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 08.07.02 02:55
Оценка:
Здравствуйте grad, Вы писали:

G>А вот что еще в голову пришло.

G>Если применять подсчет ссылок — delete вызывает экземпляр.
G>Если применять FAILED — delete вызывает объект класса.
G>New — все время вызывает объект класса.
G>Если случится так что классы фабрики и экземпляра используют разные кучи — не может ли это привести к ошибке?

Я не совсем врубился, что ты сказал, но если фабрика класса создаст объект в одной куче, а сам объект попытается себя удалить из другой, то это, естественно, приведет к траблу. Только под С++ такая проблема, скорее всего, не встанет. Там все экземпляры классов размещаются в одной куче.
Re[4]: QueryInterface brasketing
От: aik Австралия  
Дата: 08.07.02 09:50
Оценка:
Здравствуйте Алекс, Вы писали:

А>Здравствуйте grad, Вы писали:


G>>Кажется понял. Если обобщить

G>>
p->>>AddRef(); 
G>>Function(p);\\любая ф-ция, которая может потенциально оставить внешнюю ссылку на p 
p->>>Release();
G>>
прием, который помогает избавиться от опасного delete p.


А>Ну не такой он и опасный. Автор вполне мог написать:

А>
А>HRESULT hr = p->QueryInterface(riid, ppv); 
А>if (FAILED(hr)) delete p;  
А>

А>но почему-то не написал
А>

Потому что, если ты занялся COM'ом, операторы new и (особенно!!!) delete — забудь. Нельзя делать delete на интерфейс (это просто ошибка, free ругнется на порченую память в большинстве случаев), да и не COM это уже будет. Также нельзя полагаться на значения, возвращаемые AddRef'ом и Release'ом, хочется — откажись от COM.
Автор сделал скобки для того, чтобы по выходу из QueryInterface (а на ее месте могло быть что угодно) указатель был все еще валидным, мало что там функция захочет сделать, может, она подчищает за собой лишние ссылки и может лишним релизом грохнуть объект.
И кто думает, что QI выдаст плохой HRESULT, если объект уже удален — наивны. Вернет мусор или шлепнется с исключением.
Re[5]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 08.07.02 11:35
Оценка:
Здравствуйте aik, Вы писали:

[skipped]

aik>Потому что, если ты занялся COM'ом, операторы new и (особенно!!!) delete — забудь. Нельзя делать delete на интерфейс (это просто ошибка, free ругнется на порченую память в большинстве случаев), да и не COM это уже будет. Также нельзя полагаться на значения, возвращаемые AddRef'ом и Release'ом, хочется — откажись от COM.


Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?

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


QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!

aik>И кто думает, что QI выдаст плохой HRESULT, если объект уже удален — наивны. Вернет мусор или шлепнется с исключением.


Так вернет мусор или шлепнется с исключением? Ты определись! Если p уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
Автор(ы): Том Армстронг

В этой главе, позаимствованной из книги "ActiveX-Создание Web-приложений"
Тома Армстронга, рассматриваются основные понятия модели COM, такие как
интерфейс IUnknown, GUID, фабрики классов и т. д. Кроме того, автор приводит
примеры реализации COM-клиентов и COM-серверов с использованием языка C++,
Visual Basic и библиотеки ATL.
и все будет пучком!
Re[6]: QueryInterface brasketing
От: aik Австралия  
Дата: 08.07.02 11:52
Оценка: -2
Здравствуйте Алекс, Вы писали:

aik>>Потому что, если ты занялся COM'ом, операторы new и (особенно!!!) delete — забудь. Нельзя делать delete на интерфейс (это просто ошибка, free ругнется на порченую память в большинстве случаев), да и не COM это уже будет. Также нельзя полагаться на значения, возвращаемые AddRef'ом и Release'ом, хочется — откажись от COM.


А>Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?


Release и delete — взаимоисключающие операции в случае COM. delete вызывать нельзя, это убивает смысл COM'а как ориентированной на интерфейсы системы.
А ругаться будет crt, если объект держит 2 интерфейса и ты будешь делать delete по адресу второго интерфейса.

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


А>QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!


Примеры как раз и созданы для демонстрации общего подхода. QI не вызовет релиза, ежу понятно :)

aik>>И кто думает, что QI выдаст плохой HRESULT, если объект уже удален — наивны. Вернет мусор или шлепнется с исключением.

А>Так вернет мусор или шлепнется с исключением? Ты определись! Если p уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
Автор(ы): Том Армстронг

В этой главе, позаимствованной из книги "ActiveX-Создание Web-приложений"
Тома Армстронга, рассматриваются основные понятия модели COM, такие как
интерфейс IUnknown, GUID, фабрики классов и т. д. Кроме того, автор приводит
примеры реализации COM-клиентов и COM-серверов с использованием языка C++,
Visual Basic и библиотеки ATL.
и все будет пучком!


p может указывать на только что освобожденную память из-под объекта или на память, похожую на объект. Мусор бывает разный.

Ты не о том говоришь. Я говорю о примере — зачем сделано так как сделано и почему нельзя вызывать delete на интерфейсе. Вы же все пытаетесь показать, что пример плохой и предлагаете корявые решения.
btw по ATL книжки читать плохо, MSDN — тоже, много ошибок. Лучше читать ATL'ные хидеры (atlbase и atlcom).

В общем, форумы здесь — шняга, не то, что статьи...
Re: Скобки AddRef/Release
От: Vi2 Удмуртия http://www.adem.ru
Дата: 08.07.02 13:20
Оценка: 4 (1)
Здравствуйте grad, Вы писали:

G>Пример из Д.Бокса

G>STDMETHODIMP GorillaClass::CreateInstance(IUnknown *pUnkOuter,
G>                                      REFIID riid,
G>                      void** ppv)
G>{
G>  *ppv = 0;
G>  
G>  if(pUnkOuter !=0)
G>      return CLASS_E_NOAGGREGATION;

G>  Gorilla* p = new Gorilla;
G>  
G>  if(p == 0)
G>      return E_OUTOFMEMORY;

Vi2 - объект создался: будем его использовать - мы должны поиметь объект в свою собственность

G>  p->AddRef();

...
G>//  HRESULT hr = p->QueryInterface(riid, ppv);
...
Vi2 - здесь может быть много операторов с разными функциями. То, что используется "простая" и понятная функция
Vi2 - QueryInterface, никак не опровергает "стандартности технологии". Тем более Дон Бокс пишет правильно,
Vi2 - не мудрствуя, не оптимизируя. Естественно, не мешая это делать Вам при более детальном ознакомлении с
Vi2 - материалом.

G>  p->Release();

Vi2 - закончили работу собъектом: удаляем его (для себя), т.е. свой счётчик. Другие счётчики нас не волнуют.

G>  return hr;
G>}

G> утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release
G>вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни.
G>Может ли кто-нибудь из присутствующих господ меня разубедить?

Разубеждать и не надо, потому что это действительно "стандартная технология заключения в скобки AddRef/Release".
Стандартная в том плане, что так безопасно вызывать любой код примера, который понадобится Дон Боксу в последующем.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: QueryInterface brasketing
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.07.02 14:03
Оценка:
Здравствуйте Алекс, Вы писали:

А>[skipped]


VD>>delete-ов сдесь вообще нет. Это просто еще один способ вскипятить чайник.


А>но Release()-то
delete this;
вызывает!


Не факт. Может это синглетон? Или память занималась malloc-ом? Так что всегда лучше делать Release и не думать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: QueryInterface brasketing
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.07.02 14:41
Оценка: 12 (2)
Здравствуйте Алекс, Вы писали:

А>Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?


Книжки читать лучше все же тебе. Память под COM-объект может быть занята любым способом. В том числе и malloc-ом. И освобождать ее нужно из Release-а, чтобы освобождение произошло в той же куче (из которой была выделенна память).

А>QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!


QI может ниаграниченное количество раз вызывать AddReff/Release. Обычно конечно это не делается, но возможность от этого не исчезает. К тому же речь не о том. В случае успешной отработки QI вызывает AddReff, а в случае неудачи нет. При этом, в случае неудачи, чтобы ни произошло, счетчик ссылок объекта будет равен еденице, и вызов релиза его уничтожит.

А>Так вернет мусор или шлепнется с исключением? Ты определись!


Да ничего никто не шлепнет и не вернет. Выдадут отрицательный hr и все.

А>Если p уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
Автор(ы): Том Армстронг

В этой главе, позаимствованной из книги "ActiveX-Создание Web-приложений"
Тома Армстронга, рассматриваются основные понятия модели COM, такие как
интерфейс IUnknown, GUID, фабрики классов и т. д. Кроме того, автор приводит
примеры реализации COM-клиентов и COM-серверов с использованием языка C++,
Visual Basic и библиотеки ATL.
и все будет пучком!


Здесь конено принято на ты но такое панбратство выглядит как оскорбление. "Братаны" — это на кульном хацкере. Здесь все больше мужики.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: QueryInterface brasketing
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.07.02 14:43
Оценка:
Здравствуйте aik, Вы писали:

aik>btw по ATL книжки читать плохо, MSDN — тоже, много ошибок. Лучше читать ATL'ные хидеры (atlbase и atlcom).


Согласен.

aik>В общем, форумы здесь — шняга, не то, что статьи...


Я не понял, это ты статьи наши плохо оценил или форумы?

Кто такая "шняга"?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 09.07.02 04:38
Оценка:
Здравствуйте aik, Вы писали:

aik>Release и delete — взаимоисключающие операции в случае COM. delete вызывать нельзя, это убивает смысл COM'а как ориентированной на интерфейсы системы.

aik>А ругаться будет crt, если объект держит 2 интерфейса и ты будешь делать delete по адресу второго интерфейса.

Ты вообще о чем? Речь идет про ФАБРИКУ КЛАССА. Прочти первый пост!

aik>Ты не о том говоришь. Я говорю о примере — зачем сделано так как сделано и почему нельзя вызывать delete на интерфейсе. Вы же все пытаетесь показать, что пример плохой и предлагаете корявые решения.


Да нормальный пример! И AddRef/Release можно и delete можно, какая разница? Вот в примерах из книг Трельсона и Роджерсона используется delete. Ты хочеш сказать, что они ламеры?

aik>btw по ATL книжки читать плохо, MSDN — тоже, много ошибок. Лучше читать ATL'ные хидеры (atlbase и atlcom).


Может bhv, а не btw? Если это по поводу Трельсона, не согласен! Очень хорошая книга (не смотря на недавний флейм) и в смысле COM, и в смысле ATL. MSDN тоже ничего, мне нравится!

aik>В общем, форумы здесь — шняга, не то, что статьи...


Да статьи тут очень приличные, материал по COM & COM+ просто тянет на приличную книжку (спасибо Владу). А про форумы ты зря, форумы — это жизнь. Здесь можно пообщаться с крутыми мастерами (Влад, Федотов, Тарасевич), получить опыт. Где ты еще такое найдешь? На работе общение с коллегами ни черта не дает, у меня тут все ламаки стопроцентные, которые лабают только на Delphi, а С++ вообще не знают! С ними что-ли общаться?

А по поводу того, что ты в этой ветке немного лоханулся, не отчаивайся! Никто же нолика не поставил!
Re[7]: QueryInterface brasketing
От: Алекс Россия http://wise-orm.com
Дата: 09.07.02 04:52
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Здравствуйте Алекс, Вы писали:


А>>Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?


VD>Книжки читать лучше все же тебе. Память под COM-объект может быть занята любым способом. В том числе и malloc-ом. И освобождать ее нужно из Release-а, чтобы освобождение произошло в той же куче (из которой была выделенна память).


Я жутко извиняюсь, но говорим мы о фабрике класса, в частности о CreateInstance(). Только фабрика класса знает где размещен объект и уж кому как не ей лучше знать как удалять объект! Я не против AddRef/Release, это дело вкуса, но нельзя говорить, что остальные способы ошибочные.

А>>QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!


VD>QI может ниаграниченное количество раз вызывать AddReff/Release. Обычно конечно это не делается, но возможность от этого не исчезает. К тому же речь не о том. В случае успешной отработки QI вызывает AddReff, а в случае неудачи нет. При этом, в случае неудачи, чтобы ни произошло, счетчик ссылок объекта будет равен еденице, и вызов релиза его уничтожит.


[skipped]

VD>Здесь конено принято на ты но такое панбратство выглядит как оскорбление. "Братаны" — это на кульном хацкере. Здесь все больше мужики.


Да зачем мне кого-то оскорблять? Я просто хотел по братски помириться, посоветовал материал и на этом бы нитка завершилась. Если я че-то обидел или оскорбил aik, то приношу свои извинения. Ничего подобного я специально сделать не хотел.
Re[3]: К обобщению
От: Vi2 Удмуртия http://www.adem.ru
Дата: 09.07.02 07:07
Оценка: 3 (1)
Здравствуйте grad, Вы писали:

G>Кажется понял. Если обобщить

G>p->AddRef(); 
G>Function(p);\\любая ф-ция, которая может потенциально оставить внешнюю ссылку на p 
G>p->Release();


Если уж обобщать, то следующим образом: перед передачей ссылки куда бы то ни было нужно быть увереным, что эта ссылка находится в твоей собственности. Причём без разницы может ли функция(и) потенциально оставить внешнюю ссылку на p или нет.

Поэтому вызов p->AddRef(); и есть гарантия такой уверенности в данном примере (после new Gorilla). Поскольку предыдущий оператор Gorilla* p = new Gorilla; такой уверенности не даёт.

Но если такая уверенность уже есть (предысторией указателя p), то обрамлять в AddRef/Release нет необходимости (но и ошибки тоже не будет, если и обрамить. Это будет просто перестраховка).
p->AddRef(); // после new Gorilla
  Function1(p); 
  ...
  //p->AddRef(); // p уже имеет "твою" собственность
    Function2(p); 
  //p->Release();

  p->AddRef(); // p уже имеет "твою" собственность, но всё равно можно
    Function2(p); 
  p->Release();

  ...
p->Release();
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.