Как членский метод мог удалить объект?

Я в настоящее время изучаю COM, и следующий код смутил меня.

STDMETHODIMP _(ULONG) ComCar::Release()
{
  if(--m_refCount==0)
    delete this; // how could this "suicide" deletion be possible?
  return m_refCount;
}

Я задаюсь вопросом, как могло быть возможно удалить экземпляр объекта в рамках своего членского метода? Таким образом, я сделал следующий эксперимент:

class A
{
public:
    void Suicide(void);
    void Echo(void);
    char name;
};

void A::Echo(void)
{
    ::printf("echo = %c\n",name);
}

void A::Suicide(void)
{
    delete this;
}

int main(void)
{
    A a;
    a.name='a';
    a.Suicide(); //failed
}

И выполнение делает отказавший в a. Самоубийство (). Отчет об отладке некоторое "Неудавшееся Утверждение Отладки". Кто-то мог пролить некоторый свет на меня? Причина я - полностью новичок на COM.

Связанный поток здесь: Вопрос о Выпуске COM () метод

5
задан Community 23 May 2017 в 12:19
поделиться

6 ответов

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

-121--4092808-

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

Члены функции могут удалить этот - если они знают, что этот указатель был динамически выделен (через новый ). Однако они не могут получить доступ к членам после этого пункта, поэтому строго говоря, приведенный вами пример:

STDMETHODIMP _(ULONG) ComCar::Release()
{
  if(--m_refCount==0)
    delete this; // how could this "sucide" deletion be possible?
  return m_refCount;
}

приводит к неопределенному поведению в операторе return .

7
ответ дан 18 December 2019 в 06:34
поделиться

Измените основной текст на:

A* a = new A();
a->name='a';
a->Sucide();

You Конечно, можно удалить только то, что было создано с помощью new - не имеет значения, находится ли это удаление в функции-члене или где-то еще.

10
ответ дан 18 December 2019 в 06:34
поделиться

Удалить это действительно только тогда, когда объект был выделен с помощью оператора new. Для подсчета ссылок COM в этом нет ничего необычного.

Однако есть еще одно предостережение: доступ к переменным-членам после удаления этого не определен, потому что память для объекта уже была возвращена в свободное хранилище. Это делает первый опубликованный вами пример кода. Чтобы исправить это, используйте локальную переменную:

STDMETHODIMP_(ULONG) ComCar::Release()
{
  ULONG refCount = --m_refCount;
  if(refCount==0)
    delete this;
  return refCount;
}
3
ответ дан 18 December 2019 в 06:34
поделиться

Вы не можете удалить объект, который не был выделен динамически. Объекты COM выделяются динамически.

This works:

#include <stdio.h>

class A
{
public:
    void Sucide(void);
    void Echo(void);
    char name;
};

void A::Echo(void)
{
    ::printf("echo = %c\n",name);
}

void A::Sucide(void)
{
    delete this;
}

void main(void)
{
    A *a = new A;
    a->name='a';
    a->Sucide(); // works
}
2
ответ дан 18 December 2019 в 06:34
поделиться

Для этого есть простая причина. new и delete должны совпадать.

Поэтому если вы создаете объект в dll и передаете его в другую часть (exe, dll), то время выполнения C может отличаться. В этом случае вы не сможете вызвать delete, потому что время выполнения не знает об указателе, который вы хотите удалить. Это может привести к сбою.

Из-за этого хорошим решением является интеграция метода самоубийства. В Com он представляет собой пару методов.

AddRef
Release

что означает, что указатель имеет счетчик, чтобы помнить, сколько владельцев у объекта. Только если последний владелец вызывает delete, объект действительно удаляется.

Но я думаю, что в приведенной вами реализации есть ошибка.

return m_refCount;

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

STDMETHODIMP _(ULONG) ComCar::Release()
{
  if(--m_refCount==0) {
    delete this; // how could this "sucide" deletion be possible?
    return 0;
  }
  return m_refCount;
}
1
ответ дан 18 December 2019 в 06:34
поделиться

Используйте new для выделения нового объекта класса, который вы собираетесь уничтожить, вызвав delete.

1
ответ дан 18 December 2019 в 06:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: