Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Удаление указателя TStreamAdapter

11
17 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
IPersistStreamInit *psi;
WB->Document->QueryInterface(IID_IPersistStreamInit,(void **)&psi);

TMemoryStream *olds = new TMemoryStream();
TStreamAdapter *sa1 ;
sa1 = new TStreamAdapter(olds, soReference);
psi->Save(*sa1, true);
...
...
...
delete sa1; // тут AV

как правильно удалить sa1?
sa1->Free() тоже не проходит
240
17 октября 2007 года
aks
2.5K / / 14.07.2006
а psi->Release() сделать?
про TMemoryStream ниче незнаю. ))

Кстати для работы с COM очень удобно юзать ATL-ные обертки типа
 
Код:
template<class T>
class CComPtr

и

template<class T, const IID* piid = &__uuidof(T)>
class CComQIPtr: public CComPtr<T>
11
17 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
вот полный код psi->Release() тут не при чем:

Код:
IPersistStreamInit *psi;
  WB->Document->QueryInterface(IID_IPersistStreamInit,(void **)&psi);

  void *buff1 = malloc (DM->Query1BodyDoc->BlobSize);
  TStream *s = DM->Query1->CreateBlobStream(DM->Query1->FieldByName("BodyDoc"), bmRead);
  s->Seek(0, soFromBeginning);
  s->Read(buff1, DM->Query1BodyDoc->BlobSize);
  s->Seek(0, soFromBeginning);


  TMemoryStream *olds = new TMemoryStream();
  TStreamAdapter *sa1 ;
  sa1 = new TStreamAdapter(olds, soReference);
  //delete sa1;  если тут удалять, то все ОК!
  //return;
  psi->Save(*sa1, true);
  void *buff2 = malloc (olds->Size);
  olds->Seek(0, soFromBeginning);
  olds->Read(buff2,olds->Size);
  olds->Seek(0, soFromBeginning);
  if (olds->Size == DM->Query1BodyDoc->BlobSize && memcmp(buff1, buff2, olds->Size) == 0) // doc wasn't changed
     {
       free(buff1);
       free(buff2);
       psi->Release();
       delete sa1;
       delete olds;

       return;
     }


мешает psi->Save(...)
11
17 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
помогло обнуление указателя:

sa1 = NULL;
delete sa1;

так правильно вообще будет?
240
17 октября 2007 года
aks
2.5K / / 14.07.2006
Цитата: oxotnik333
помогло обнуление указателя:

sa1 = NULL;
delete sa1;

так правильно вообще будет?



Так 100% не правильно. Ты же реальный указатель тут теряешь, а вместо него пытаешся обнулить NULL.

3.2K
17 октября 2007 года
nikipelovav
152 / / 12.04.2006
Прочти справку по IUnknown::Release.
Там сказано, что не всегда метод Release приводит к удалению объекта.
В твоём примере, если не удалён psi, он может мешать удалять sal.
11
17 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
пробовал по разному, и вот так:
delete psi;
delete sa1;

один хрен
240
17 октября 2007 года
aks
2.5K / / 14.07.2006
Цитата: oxotnik333
пробовал по разному, и вот так:
delete psi;
delete sa1;

один хрен


Почитай документацию по COM.
таким образом: delete psi;
ты не освободишь COM объект.

489
17 октября 2007 года
NeO_u
277 / / 11.10.2006
Помойму, там вылает AV потому, что то время как ты удаляешь sa1, его еще использует psi...т.е. та область памяти, которую ты пытаешься очистить еще используется. это же видно и из примера который ты выложил:
 
Код:
sa1 = new TStreamAdapter(olds, soReference);
  //delete sa1;  если тут удалять, то все ОК!
  //return;
  psi->Save(*sa1, true);


т.е. прежде чем пытаться удалить этот указатель, поудаляй вначале все зависимости, скорее всего в psi, есть какой нибудь метод или функция, типа Close, которая будет закрывать этот sa1.
Или, возможен такой вариант: что сама функция Save затирает ту область памяти..т.е. освобождает объект. надо вообще почитать документацию для более конкретного ответа. Я уже сталкивался с такими фишками борланда...что save удаляет самостоятельно объект, тоже долго мучался в поиске решения...
11
17 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
делал по разному:
в т.ч. и так:
psi->Release(); //отсвобождение COM объекта
delete olds; // удаление "связанной" с sa1 памяти
delete sa1;
один фиг AV и все тут
3.2K
17 октября 2007 года
nikipelovav
152 / / 12.04.2006
Помоему проблема в строке
 
Код:
psi->Save(*sa1, true);


В справке по IPersistStream::Save написано
 
Код:
Saves an object to the specified stream.

HRESULT Save(
    IStream *pStm,  //Pointer to the stream where the object is to be saved
    BOOL fClearDirty    //Specifies whether to clear the dirty flag
   );


а в своём примере ты передаёшь не АДРЕС: sa1, а ОБЪЕКТ: *sa1 !
Возможно это всё и портит!
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
я же удаляю по почереди все связанные объекты, причем sa1 самым последним
240
18 октября 2007 года
aks
2.5K / / 14.07.2006
А что возвращает Release()?
Плюс как написал nikipelovav - странный способ передачи значения в метод Save. Конечно оперетор * может быть переопределен для класса TStreamAdapter, а я не знаю что это за класс, так как не пользуюсь Borland-ом. Но ты все же уверен, что *sa1, возвращает именно то что нужно для передачи в Save() ?
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
Цитата:
А что возвращает Release()?


S_OK
вся эта конструкция работает абсолютно правильно...
т.е. из IPersistStreamInit в TMemoryStream посредством TStreamAdapter передается поток, передается полностью, правильно и 100% работает...
единственный косяк с удалением этого промежуточного звена TStreamAdapter.
в общем и целом это не критично, однако, если в течении работы проги открыть около 100 документов, тогда потребляемая память возрастает на 5-10 метров, т.е. на 20-50 %, что не есть гуд...

3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Можешь указать заголовочный файл для IPersistStreamInit. У себя в Builder-е не могу найти. Справка Win SDK пишет только о IPersistStream.
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
ocidl.h
он там определяется
а подключается к проекту судя по всему вот так:
#include <atl\atlvcl.h>
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Я всё таки сомневаюсь в том, что *sai - это верный аргумент.
Посмотри как определён класс в ocidl.h

Код:
typedef /* [unique] */ IStream *LPSTREAM;

....

#if defined(__cplusplus) && !defined(CINTERFACE)
   
    MIDL_INTERFACE("7FD52380-4E07-101B-AE2D-08002B2EC713")
    IPersistStreamInit : public IPersist
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE IsDirty( void) = 0;
       
        virtual HRESULT STDMETHODCALLTYPE Load(
            /* [in] */ LPSTREAM pStm) = 0;
       
        virtual HRESULT STDMETHODCALLTYPE Save(
            /* [in] */ LPSTREAM pStm,
            /* [in] */ BOOL fClearDirty) = 0;
       
        virtual HRESULT STDMETHODCALLTYPE GetSizeMax(
            /* [out] */ ULARGE_INTEGER *pCbSize) = 0;
       
        virtual HRESULT STDMETHODCALLTYPE InitNew( void) = 0;
       
    };
   
...


Ты пробовал вместо *sai передавать в метод Save - sai ?
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Ещё один вопрос, так как ты привёл нам лишь часть кода.

Как Я понял, метод QueryInterface внутри себя вызывает метод IUnknown::AddRef , который ИНКРИМЕНТИРУЕТ счётчик вызовов интерфейса ( копий указателей ).

 
Код:
// выдержка из справки
The IUnknown::AddRef method increments the reference count
for a the calling interface on an object. It should be called for
every new copy of a pointer to an interface on a given object.


Метод IUnknown::Release() , наоборот, ДЕКРИМЕНТИРУЕТ счётчик вызовов интерфейса ( копий указателей ). И лишь в случае СЧЁТЧИК = 0 очищает память!

 
Код:
// выдержка из справки
Decrements the reference count for the calling interface on a object.
If the reference count on the object falls to 0, the object is freed from memory.


Возможно, ты в другом месте программы делаешь ещё вызов

 
Код:
WB->Document->QueryInterface(IID_IPersistStreamInit,(void **)&psi);


и в твоем проблемном месте, поток sai занят?

P.S.: Для меня эта тема новая, свои мысли высказываю только на основе анализа справки ;)
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
1. TStreamAdapter как из название следует, является промежуточным звеном (адаптером) между IStream и TStream, поэтому когда делается *sa1 = new TStreamAdapter (...), sa1 апеврящается в IStream.

2. QueryInterface вызываю всего один раз (видно по коду который выкладывал, он полный, за исключением записи в файл, но того что выложил достаточно для понятия проблемы)

3. psi->Release() делал столько раз сколько и QueryInterface (т.о. счетчик должен быть обнулен)

4. в качестве ЗЫ: облазил весь инет, нашел кучу примеров сохранения WB в поток/файл, но нигде в С++ вариантах не удаляется TStreamAdapter, отднако в дельфевских кодах вызывается sa.Free(); (через нее тоже пробовал, монопенисуально delete)
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Может всё значительно просто:

В справке по деструктору TStreamAdapter написано

 
Код:
Most applications do not need to explicitly free the TStreamAdapter instance.
Instead, it is freed automatically when its reference count drops to 0.
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
А еще в справке по свойству RefCount написано
Код:
Indicates the number of interface pointers currently dependent upon the object.

__property int RefCount = { read=FRefCount };

Description

RefCount defines the lifetime of the object.
When RefCount is zero, the object is destroyed.

RefCount is incremented by calls to the _AddRef method
and decremented by the _Release method.


Выходит что после psi->Release(); - sai->RefCount = 0 и sai автоматически удаляется!
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
sai->RefCount = 40 у меня
откуда так много ума не приложу, когда РЕАЛЬНО вызывается ОДИН раз..
а весь гемор в том что память жрет и не освобождает
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Попробуй пока так

 
Код:
while ( psi->Release() ) {} // пока счётчик не ноль


Это очистит RefCount в 0 и возможно освободит память.
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
А ты можешь подробнее расказать, что такое WB? Уж больно интересно понять что ты делаешь, может и мне когда-нибудь пригодиться ;)
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
delete sa1; - "Invalid pointer operation"
уже лучше )))
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
Цитата: nikipelovav
А ты можешь подробнее расказать, что такое WB? Уж больно интересно понять что ты делаешь, может и мне когда-нибудь пригодиться ;)



TCppWebBrowser *WB;

3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
Если Я правильно понял, твой код отслеживает момент изменения веб странички.

Я обратил внимание на то, что создавая поток BLOB данных ты его не удаляешь!

Код:
TStream *s = DM->Query1->CreateBlobStream(DM->Query1->FieldByName("BodyDoc"), bmRead);
 ...

    if (olds->Size == DM->Query1BodyDoc->BlobSize && memcmp(buff1, buff2, olds->Size) == 0) // doc wasn't changed
     {
       free(buff1);
       free(buff2);            
       psi->Release();
       delete sa1;
       delete olds;

       return;
     }


нет строки "delete s;". Возможно здесь причина засорения памяти.

Ты проверяешь изменение по таймеру? Если да, то отслеживаешь ли ты ситуацию повторного запуска обработчика, т.е. когда один обработчик выполняется, а второму "уже время".
11
18 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
отслеживаю на OnBeforeNavigate2
TStream виртуальный класс ему не требуется new\delete
3.2K
18 октября 2007 года
nikipelovav
152 / / 12.04.2006
2 вопроса:

1) Насчёт
Цитата:

отслеживаю на OnBeforeNavigate2



В справке написано, что это событие вызывается перед переходом на другую страницу, вызванному методом Navigate или кликом на ссылку. Но ведь в этот момент WB отображает туже страницу что и какое-то время назад, по всей видимости, ту страницу, которая сохранена у тебя в BLOB поле.

По идее надо использовать событие OnDocumentComplet, т.е. когда страница полностью загружена,
и в этот момент сравнивать с предидущим состоянием.

2) Насчёт

Цитата:

TStream виртуальный класс ему не требуется new\delete


пожалуйста обоснуй.

Я работаю в своей БД с BLOB полями и удаляю поток данных после использования, поскольку так написано в справке:

Код:
CreateBlobStream, Edit example

The following example copies the data in the Notes field of Table1 to the Remarks field of ClientDataSet1.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TBlobStream *Stream1;
  TStream *Stream2;

  Stream1 = new TBlobStream(Table1Notes, bmRead);
  try
  {
    ClientDataSet1->Edit();
    // here’s another way to create a blob stream
    Stream2 = ClientDataSet1->CreateBlobStream(ClientDataSet1->FieldByName("Remarks"), bmReadWrite);
    try
    {
      Stream2->CopyFrom(Stream1, Stream1->Size);
      ClientDataSet1->Post();
    }
    __finally
    {

      delete Stream2;
    }
  }
  __finally
  {
    delete Stream1;
  }
}


Вот так, например, Я копирую содержимое BLOB поля в поток в памяти
 
Код:
TMemoryStream* MS = new TMemoryStream();
TStream *BS = myDataSet->CreateBlobStream( myDataSet->FieldByName( myFieldName ), bmRead );
MS->CopyFrom( BS, BS->Size );
delete BS;

...
далее работаю с потоком в памяти MS
...
11
19 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
по поводу delete TStream, спасибо за подсказку (сам думал, раз нет new, не должно быть и delete)
по поводу проверки на изменение документа:
прога организована т.о. что перед тем как загрузить новую страницу, она проверяет старую(сравнивает с БД), т.е. получается редактировался документ, юзер захотел перейти на другой, автоматом вызывается проверка перед тем как загрузится новый документ (т.е. перед тем как состояние БД изменится)
3.2K
19 октября 2007 года
nikipelovav
152 / / 12.04.2006
Так что, delete TStream - помогло с проблемой "мусора в памяти"?
И как ситуация с sai. Ты писал о другом сообщении об ошибке. Пробовал моё предложение while ( psi->Release() )?
11
19 октября 2007 года
oxotnik333
2.9K / / 03.08.2007
подсказали несколько другой код через CComQIPtr & auto_ptr,
но все это вопрос не сильно решает... как росла память так и растет
while ( psi->Release() ) пробовал после этого и вылезла уже другая ошибка.
короче через ComQIPtr буду дклать, так поменьше жрет памяти
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог