2009-09-25 2 views
0

У меня есть объект, который читает из сокета непрерывно, как показано ниже:поведение C++ после разрушения

void CSocketReader::ReadComplete () 
{ 
messageProcessor->ResponseReceived (response); 
read(); 
} 

void CSocketReader::read() 
{ 
socket.read(response); 
} 

Моя проблема, в зависимости от реакции и на протоколе, что я запустившего метод ResponseReceived может привести к удаление объекта CSocketReader. Когда метод ResponseReceived возвращает объект, на который указывает этот указатель, был бы удален (но по какой-то причине мне не известен, этот указатель не является NULL даже после его удаления !!). Затем выполняется метод чтения, и программа выходит из строя в режиме чтения. Как я могу надежно обнаружить, что метод, который выполнялся на объекте, был удален.

Пожалуйста, помогите.

+0

определение функции все еще существует, даже после удаления объекта. вызов функции должен быть закодирован на языке ассемблера. , что объясняет, почему вызов функции все еще выполняется. правильно. –

+0

Я добавил еще один комментарий к концу ответа Йеспера. – ChrisW

ответ

4

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

Вы не можете установить флаг «bool amDeleted» внутри самого объекта (потому что после его удаления этот флаг/память может быть повторно использован/перезаписан каким-либо другим).

Единственный надежный способ сделать это (что я могу думать) было бы, как это ...

class Foo 
{ 
    //have a static set of all valid Foo instance pointers 
    typedef std::set<Foo*> Set; 
    static Set s_set; 

public: 
    Foo() 
    { 
    s_set.insert(this); 
    } 

    //ditto in every other Foo constructor, including the copy constructor 

    ~Foo() 
    { 
    s_set.remove(this); 
    } 

private: 
    static bool exists(Foo* foo) 
    { 
    return s_set.find(foo) != s_set.end(); 
    } 
}; 

[... или поточно-Set, если строится Foo/Работа/уничтожен более чем один поток].

+0

Это то, что я сделал, за исключением того, что вместо статического хэш-файла я использовал статический std :: set. – ChrisW

+0

ах не читал его правильно ... Я, хотя вы также играли с удаленным флагом ... Я удалю свой комментарий. – Toad

+0

Это решение работало без существенных изменений в источнике. Благодарю. – ardsrk

8

Что значение this указателя после того, как объект был разрушен не определено в стандарте С ++, так что это не должно быть сюрпризом, что this не NULL - C++ не требуется, чтобы установить его в NULL для вас ,

Если объект messageProcessor уничтожает объект CSocketReader, который его назвал, тогда дизайн вашей программы немного странный. По крайней мере, я сделал бы ResponseReceived функция, например, вернуть bool, которое true, если он удалил CSocketReader, так что вы можете сделать:

if (!messageProcessor->ResponseReceived(response)) { 
    return; 
} 

Вернись немедленно. Но даже это может быть небезопасно; вы не должны создавать свою программу таким образом, чтобы код мог быть выполнен на уничтоженном объекте.

+1

+1 и вообще, операция 'delete' не изменяет его операнд. –

+0

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

+0

Это опрятное решение. За исключением того, что если метод ResponseReceived приводит к цепочке вызовов методов, и решение об удалении объекта SocketReader выполняется при последнем вызове, мне нужно будет вернуть bool по всей цепочке вызовов. – ardsrk

2

Удаление объекта не изменяет указатели на этот объект. Реализация этого потребует, чтобы каждый объект «знал» обо всех указателях на него, поэтому он мог бы установить их все в NULL в своем деструкторе. Это было бы кошмаром производительности и памяти, если это даже возможно реализовать. Это, безусловно, стоило бы большой сложности, поскольку функция не всегда нужна. C++ уклоняется от этого типа дизайна, предпочитая не «заставлять» вас платить за функции, которые вам не нужны.

Одним из исправлений может быть не удаление объекта, но, возможно, просто установите флаг «deleteMe», который затем можно проверить, если вы знаете, что больше не получаете доступ к объекту.

0

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

0

delete'ing объекта не устанавливает его значение в ноль - он просто запускает деструктор (ы) и освобождает память. Если messageProcessor-> ResponseReceived (ответ); функция может удалить экземпляр объекта, который вызывает эту функцию, тогда у вас проблемы - значение этого указателя при возврате не изменится (C++ не перепишет стек вызовов для вас), но теперь вы находитесь в неопределенное поведение земли. Более того, другие удерживаемые указатели на этот объект будут по-прежнему указывать на память, в которой находился объект, поскольку нет возможности найти все ссылки и переписать их - указатель - это просто хранимое значение, которое интерпретируется как адрес.

Самое простое решение - иметь сообщениепроцессор-> ResponseReceived (response); верните флаг, указывающий, следует ли продолжать - если нет, немедленно выйдите с возвратом. Лучшее решение, вероятно, должно быть перепроектировано, чтобы избежать этой ситуации.

0

после удаления указателя он не будет автоматически передаваться по нулевому значению. Вы должны явно указать значение null, если хотите.

Когда метод вызывает в классе, который больше не существует, ничего не происходит, если вы не используете одно из его свойств или полей. Таким образом, код может потенциально работать без проблем.

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

Смежные вопросы