-Поиск по дневнику

Поиск сообщений в rss_forum_sources_ru

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 29.07.2007
Записей:
Комментариев:
Написано: 80


goto vs break & continue

Среда, 22 Июля 2020 г. 02:20 + в цитатник
Wound:
Цитата JoeUser @
Если добрались, все эти ресурсы в полях класса висят без какого-то использования, только для удаления.

Что тебе мешает объявить эти ресурсы не в полях класса, а там где конкретно они нужны? Тогда они сразу же и удаляться, как только перестанут быть нужными.
В общем или лыжи не едут или я censored :-?
Тебе рассказывают про то, что хорошо бы работу с отдельными ресурсами вынести в отдельные классы, у тебя бы в таком случае код сократился бы в пять раз в твоей вырвиглазной функции, ты бы отделил логику работы приложения от логики работы с ресурсом, тем самым упростив понимание задачи.
Тут работы на максимум на пару часов, и того меньше, а ты третьи сутки сидишь - и то у тебя не так, и это у тебя не эдак.

Да тут даже вот взять если втупую не думая твой код скопипастить в класс, получается куда лучше и понятнее чем у тебя сейчас есть.
Допустим на примере сессии:
Какая то примитивная обертка(тупо взял все вызовы твоих функций и вынес в метод класса сессии):
    struct SLibssh2_session
    {
    SLibssh2_session()
    {
    m_session = libssh2_session_init();
    if (!m_session) {
    sftpError = sftp_error::session_error;
    throw "session is not initialized...";
    }
    }
    ~SLibssh2_session()
    {
    libssh2_session_disconnect(m_session, "Normal Shutdown, Thank you for playing!");
    libssh2_session_free(m_session);
    }
    void SetBanner(const std::string& banner)
    {
    if(!libssh2_session_banner_set(m_session, banner.c_str()))
    {
    sftpError = sftp_error::session_error;
    throw "can't set baner...";
    }
    }
    void Handshake(int socket)
    {
    if (libssh2_session_handshake(m_session, socket))
    {
    sftpError = sftp_error::handshake_error;
    throw "handshake_error...";
    }
    }
    void SetBlocking(int blocking)
    {
    // перевод в неблокируемый режим
    libssh2_session_set_blocking(m_session, blocking);
    }
    //! Эти методы возможно должны быть вынесены в другой класс, лень заморачиваться, просто ради показать идею.
    std::string HostKeyHash(int flag)
    {
    return libssh2_hostkey_hash(m_session, flag);
    }
    void LoginByUserPwd(const char* login, const char* pwd)
    {
    int ret = 0;
    while ((ret = libssh2_userauth_password(m_session, login, pwd)) == LIBSSH2_ERROR_EAGAIN);
    if (ret) {
    sftpError = sftp_error::auth_error;
    throw "error during LoginByUserPwd...";
    }
    }
    void LoginByPublickey_frommemory(...)
    {
    while ((ret = libssh2_userauth_publickey_frommemory(
    m_session,
    Auth->login.toLocal8Bit().data(),
    Auth->login.length(),
    Auth->public_array.data(),
    Auth->public_array.size(),
    Auth->private_array.data(),
    Auth->private_array.size(),
    Auth->password.toLocal8Bit().data()
    )) == LIBSSH2_ERROR_EAGAIN);
    if (ret) {
    sftpError = sftp_error::auth_error;
    throw "Error in LoginByPublickey_frommemory...";
    }
    }
    private:
    LIBSSH2_SESSION* m_session;
    }

Использование, при этом логика твоего приложения никак не изменилась:
    void mov::qt::sftp_class::slotLogin() {
    struct addrinfo hint;
    struct addrinfo *addrs;
    struct sockaddr_in *sin;
    const char *fingerprint;
    struct addrinfo *p;
    int ret;
    bool found;
    sftpError = sftp_error::no;
    if (sftpState == sftp_state::ready && Auth->authState == auth_state::ok) {
    // инициализация библиотеки
    if (libssh2_init(0) != 0) {
    sftpError = sftp_error::libssh2_error;
    return;
    }
    // поиск адреса хоста
    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_NUMERICHOST;
    hint.ai_family = AF_UNSPEC;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    ret = getaddrinfo(Host.toLocal8Bit().data(), NULL, &hint, &addrs);
    if (ret == EAI_NONAME) {
    hint.ai_flags = 0;
    ret = getaddrinfo(Host.toLocal8Bit().data(), NULL, &hint, &addrs);
    }
    if (ret != 0) {
    sftpError = sftp_error::resolve_error;
    goto cleanup_libssh2_init;
    }
    found = false;
    for (p = addrs; p != nullptr; p = p->ai_next) {
    if (p->ai_family == AF_INET) {
    found = true;
    sin = reinterpret_cast(p->ai_addr);
    break;
    }
    }
    if (!found) {
    sftpError = sftp_error::ip4_error;
    goto cleanup_libssh2_init;
    }
    // создание сокета
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
    sftpError = sftp_error::socket_error;
    goto cleanup_libssh2_init;
    }
    sin->sin_family = AF_INET;
    sin->sin_port = htons(Port);
    // коннект
    ret = ::connect(sock, (struct sockaddr *)(sin), sizeof(struct sockaddr_in));
    if (ret != 0) {
    sftpError = sftp_error::connect_error;
    goto cleanup_socket;
    }
    //======================Было=============================================
    // создание сессии
    // session = libssh2_session_init();
    // if (!session) {
    // sftpError = sftp_error::session_error;
    // goto cleanup_socket;
    // }
    // // установка баннера
    // if (libssh2_session_banner_set(session, "SSH-2.0-OpenSSH_LIBSSH2_1.9.0") != 0) {
    // sftpError = sftp_error::session_error;
    // goto cleanup_session;
    // }
    // // рукопожатие
    // if (libssh2_session_handshake(session, sock)) {
    // sftpError = sftp_error::handshake_error;
    // goto cleanup_session;
    // }
    // // перевод в неблокируемый режим
    // libssh2_session_set_blocking(session, 0);
    // получение отпечатка
    //fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    // авторизация
    // if (Auth->authType == auth_type::login) {
    // while ((ret = libssh2_userauth_password(
    // session,
    // Auth->login.toLocal8Bit().data(),
    // Auth->password.toLocal8Bit().data()
    // )) == LIBSSH2_ERROR_EAGAIN);
    // if (ret) {
    // sftpError = sftp_error::auth_error;
    // goto cleanup_session;
    // }
    // } else {
    // while ((ret = libssh2_userauth_publickey_frommemory(
    // session,
    // Auth->login.toLocal8Bit().data(),
    // Auth->login.length(),
    // Auth->public_array.data(),
    // Auth->public_array.size(),
    // Auth->private_array.data(),
    // Auth->private_array.size(),
    // Auth->password.toLocal8Bit().data()
    // )) == LIBSSH2_ERROR_EAGAIN);
    // if (ret) {
    // sftpError = sftp_error::auth_error;
    // goto cleanup_session;
    // }
    // }
    //=======================Стало============================================
    try
    {
    SLibssh2_session session;
    session.SetBanner("SSH-2.0-OpenSSH_LIBSSH2_1.9.0");
    session.Handshake(sock);
    session.SetBlocking(0);
    fingerprint = HostKeyHash(LIBSSH2_HOSTKEY_HASH_SHA1);
    if (Auth->authType == auth_type::login)
    {
    session.LoginByUserPwd(Auth->login.toLocal8Bit().data(), Auth->password.toLocal8Bit().data());
    }
    else
    {
    session.LoginByPublickey_frommemory(...);
    }
    }
    catch(const char* error)
    {
    error;
    }
    //====================================================================
    // инициализация ftp-сессии
    do {
    sftp_session = libssh2_sftp_init(session);
    if (!sftp_session) {
    if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN)
    waitsocket(sock, session);
    else {
    sftpError = sftp_error::auth_error;
    goto cleanup_session;
    }
    }
    } while (!sftp_session);
    // все четко и дерзко
    sftpState = sftp_state::logged_in;
    return;
    // аварийная очистка
    // cleanup_session:
    // libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing!");
    // libssh2_session_free(session);
    cleanup_socket:
    #ifdef WIN32
    closesocket(sock);
    #else
    close(sock);
    #endif
    cleanup_libssh2_init:
    libssh2_exit();
    }
    }


Добавлено
Разнеси оставшиеся ресурсы с очистками по классам, у тебя от функции останется 40 очевидных строк, которые будут понятны с полувзгляда.
Обертки сами - они так же примитивные, по сути отдельные операции суешь в методы, выделение ресурса - конструктор, удаление - деструктор.
Посмотри на получившийся класс - там сразу видно что это тупо обертка над Си функциями, ошибки детектятся мгновенно, т.к. каждая функция в отдельном методе, и если что можно сосредоточится на методе в 5 строк, нежели на функции в 200 строк вырвиглазного кода. Ошибку в 5 строках кода - найти проще, чем в 200 строках. Т.е. по сути класс ниочемный, но тем не менее - он логику работы с твоей сессией сократил в 3-4 раза.
А если еще прикрутить логирование, в каждый метод, то тут как бы вообще даже если и будет какой то баг, то его без отладки найти будет дело трех минут. В твоем коде не то что бы отладка, тут без двух литров не обойтись чтоб понять где там что произошло.

https://forum.sources.ru/index.php?showtopic=362619&view=findpost&p=3834840

Метки:  

 

Добавить комментарий:
Текст комментария: смайлики

Проверка орфографии: (найти ошибки)

Прикрепить картинку:

 Переводить URL в ссылку
 Подписаться на комментарии
 Подписать картинку