утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release
вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни.
Может ли кто-нибудь из присутствующих господ меня разубедить?
Re: QueryInterface brasketing
От:
Аноним
Дата:
04.07.02 13:56
Оценка:
Здравствуйте grad, Вы писали:
G>Пример из Д.Бокса G>
утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release G>вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни. G>Может ли кто-нибудь из присутствующих господ меня разубедить?
Я могу ошибаться, но возможно это сделано для автоматического удаления объекта, в случае если QueryInterface не пройдет.
После вызова new класс создается с нулевым счетчиком ссылок. AddRef увеличивает счетчик ссылок. Если QueryInterface не прошел, последующий Release обнулит счетчик ссылок и объект удалиться.
утверждается (автором), что "этот прием использует стандартную технологию заключения в скобки AddRef/Release G>вызова QueryInterface". Я не понимаю зачем это нужно в данном случае, по моему вызовы излишни. G>Может ли кто-нибудь из присутствующих господ меня разубедить?
Чтоб объект уничтожился, если QueryInterface вернет плохой hr.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
А вот что еще в голову пришло.
Если применять подсчет ссылок — delete вызывает экземпляр.
Если применять FAILED — delete вызывает объект класса.
New — все время вызывает объект класса.
Если случится так что классы фабрики и экземпляра используют разные кучи — не может ли это привести к ошибке?
Здравствуйте grad, Вы писали:
G>А вот что еще в голову пришло. G>Если применять подсчет ссылок — delete вызывает экземпляр. G>Если применять FAILED — delete вызывает объект класса. G>New — все время вызывает объект класса. G>Если случится так что классы фабрики и экземпляра используют разные кучи — не может ли это привести к ошибке?
Я не совсем врубился, что ты сказал, но если фабрика класса создаст объект в одной куче, а сам объект попытается себя удалить из другой, то это, естественно, приведет к траблу. Только под С++ такая проблема, скорее всего, не встанет. Там все экземпляры классов размещаются в одной куче.
Потому что, если ты занялся COM'ом, операторы new и (особенно!!!) delete — забудь. Нельзя делать delete на интерфейс (это просто ошибка, free ругнется на порченую память в большинстве случаев), да и не COM это уже будет. Также нельзя полагаться на значения, возвращаемые AddRef'ом и Release'ом, хочется — откажись от COM.
Автор сделал скобки для того, чтобы по выходу из QueryInterface (а на ее месте могло быть что угодно) указатель был все еще валидным, мало что там функция захочет сделать, может, она подчищает за собой лишние ссылки и может лишним релизом грохнуть объект.
И кто думает, что QI выдаст плохой HRESULT, если объект уже удален — наивны. Вернет мусор или шлепнется с исключением.
[skipped]
aik>Потому что, если ты занялся COM'ом, операторы new и (особенно!!!) delete — забудь. Нельзя делать delete на интерфейс (это просто ошибка, free ругнется на порченую память в большинстве случаев), да и не COM это уже будет. Также нельзя полагаться на значения, возвращаемые AddRef'ом и Release'ом, хочется — откажись от COM.
Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?
aik>Автор сделал скобки для того, чтобы по выходу из QueryInterface (а на ее месте могло быть что угодно) указатель был все еще валидным, мало что там функция захочет сделать, может, она подчищает за собой лишние ссылки и может лишним релизом грохнуть объект.
QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!
aik>И кто думает, что QI выдаст плохой HRESULT, если объект уже удален — наивны. Вернет мусор или шлепнется с исключением.
Так вернет мусор или шлепнется с исключением? Ты определись! Если p уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
Здравствуйте Алекс, Вы писали:
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 уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
p может указывать на только что освобожденную память из-под объекта или на память, похожую на объект. Мусор бывает разный.
Ты не о том говоришь. Я говорю о примере — зачем сделано так как сделано и почему нельзя вызывать delete на интерфейсе. Вы же все пытаетесь показать, что пример плохой и предлагаете корявые решения.
btw по ATL книжки читать плохо, MSDN — тоже, много ошибок. Лучше читать ATL'ные хидеры (atlbase и atlcom).
В общем, форумы здесь — шняга, не то, что статьи...
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".
Стандартная в том плане, что так безопасно вызывать любой код примера, который понадобится Дон Боксу в последующем.
Здравствуйте Алекс, Вы писали:
А>Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?
Книжки читать лучше все же тебе. Память под COM-объект может быть занята любым способом. В том числе и malloc-ом. И освобождать ее нужно из Release-а, чтобы освобождение произошло в той же куче (из которой была выделенна память).
А>QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!
QI может ниаграниченное количество раз вызывать AddReff/Release. Обычно конечно это не делается, но возможность от этого не исчезает. К тому же речь не о том. В случае успешной отработки QI вызывает AddReff, а в случае неудачи нет. При этом, в случае неудачи, чтобы ни произошло, счетчик ссылок объекта будет равен еденице, и вызов релиза его уничтожит.
А>Так вернет мусор или шлепнется с исключением? Ты определись!
Да ничего никто не шлепнет и не вернет. Выдадут отрицательный hr и все.
А>Если p уже указывает на мусор она вообще не вызовется! Вообщем, братан, читай книжки, статьи
Здравствуйте 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, а С++ вообще не знают! С ними что-ли общаться?
А по поводу того, что ты в этой ветке немного лоханулся, не отчаивайся! Никто же нолика не поставил!
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте Алекс, Вы писали:
А>>Какой еще free. У меня ничего никогда не ругается. И при чем здесь AddRef и Release()?
VD>Книжки читать лучше все же тебе. Память под COM-объект может быть занята любым способом. В том числе и malloc-ом. И освобождать ее нужно из Release-а, чтобы освобождение произошло в той же куче (из которой была выделенна память).
Я жутко извиняюсь, но говорим мы о фабрике класса, в частности о CreateInstance(). Только фабрика класса знает где размещен объект и уж кому как не ей лучше знать как удалять объект! Я не против AddRef/Release, это дело вкуса, но нельзя говорить, что остальные способы ошибочные.
А>>QI ни при каких обстоятельствах не вызовет Release()! Это основы СОМ!
VD>QI может ниаграниченное количество раз вызывать AddReff/Release. Обычно конечно это не делается, но возможность от этого не исчезает. К тому же речь не о том. В случае успешной отработки QI вызывает AddReff, а в случае неудачи нет. При этом, в случае неудачи, чтобы ни произошло, счетчик ссылок объекта будет равен еденице, и вызов релиза его уничтожит.
[skipped]
VD>Здесь конено принято на ты но такое панбратство выглядит как оскорбление. "Братаны" — это на кульном хацкере. Здесь все больше мужики.
Да зачем мне кого-то оскорблять? Я просто хотел по братски помириться, посоветовал материал и на этом бы нитка завершилась. Если я че-то обидел или оскорбил aik, то приношу свои извинения. Ничего подобного я специально сделать не хотел.
Здравствуйте 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();