почему boost :: bind с удаленным объектом работает? - PullRequest
1 голос
/ 24 января 2012

Посмотрите на этот код:

#include <asio.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>

#include <iostream>
using namespace std;

class acceptor
{
private:
    asio::ip::tcp::acceptor * a;
    asio::io_service &_service;
    asio::ip::tcp::endpoint ep;
public:
    acceptor(asio::io_service &service, unsigned int port)
        :_service(service), ep(asio::ip::tcp::v4(), port)
    {
        try {
            a = new asio::ip::tcp::acceptor(service, ep);
        }
        catch (asio::system_error &e) {
            cout << e.what() << endl;
        }
        continueAccept();
    }

    ~acceptor() {
        delete a;
        cout << " destroy " << endl;
    }

    void continueAccept() {
        cout << "start accepting ..." << endl;
        boost::shared_ptr<asio::ip::tcp::socket> ptr(new asio::ip::tcp::socket(_service));
        a->async_accept(*ptr, boost::bind(&acceptor::handleAccept, this, ptr, asio::placeholders::error));
    }

    void handleAccept(
        boost::shared_ptr<asio::ip::tcp::socket> &socket,
        const asio::error_code &e)
    {
        if (e == asio::error::operation_aborted) {
            cout << "handler is called by error_code : " << e.message() << endl;
        }
    }

    void close() {
        cout << "close is called ..." << endl;
        a->close();
    }
};

int main(int argc, char *argv[]) {
    asio::io_service service;
    acceptor *aa = new acceptor(service, 8899);

    service.poll();
    service.reset();

    delete aa;

    service.poll();
    service.reset();

    return 0;
}

вывод:

  • начать прием ...
  • Destory
  • обработчик вызывается с помощью error_code: операция прервана

когда я удаляю объект aa в методе main, asio :: ip :: tcp :: acceptor на деструкторе объекта a вызывает его закрытие и асинхронная операция вызывает asio :: error :: operation_aborted.

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

Вопрос: почему программа работает корректно при вызове функции над удаленным объектом методом boost?

Ответы [ 3 ]

5 голосов
/ 24 января 2012

почему программа работает корректно при вызове функции для удаленного объекта методом boost?

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

Вам не повезло, потому что ваша программа, кажется, работает.

4 голосов
/ 24 января 2012

Вызов функции-члена через неверный указатель дает неопределенное поведение.

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

Одна возможность, проиллюстрированная в некоторых примерах Asio, таких как этот , состоит в управлении классом acceptor с помощью общих указателей; наследуя от enable_shared_from_this<acceptor>, вы можете связать функцию accept с общим указателем, а не с необработанным указателем this:

a->async_accept(*ptr, 
    boost::bind(&acceptor::handleAccept, 
                shared_from_this(),                 // <--- not "this"
                ptr, asio::placeholders::error));

Тогда объект будет оставаться живым до тех пор, пока handleAccept не завершится; и дольше, если это связывает shared_from_this() с дальнейшими асинхронными операциями.

1 голос
/ 24 января 2012

Использование удаленной памяти считается неопределенным поведением .

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

...