LINUX.ORG.RU

Помогите с std::function

 


0

1

Приветствую

Суть задачи проста - получить параметры одного или всех сетевых интерфейсов, понятно что можно в векторе, например, вернуть, но можно как то вот хитрожопо сделать через std::function или что то иное есть??? Так чтобы снаружи вызова можно было построчно обработать.

код, в котором не догоняю как можно getIPs и getIP реализовать, чтобы потом их вызывать можно было???

std::string getSockToIP(const struct sockaddr * psa)
{
    uint8_t laddr = 0;
    char * addr = nullptr;
    std::string rt("");

    switch (psa->sa_family)
    {
        case AF_INET:
            addr = (char*)calloc(laddr = INET_ADDRSTRLEN, sizeof(char));
            break;
        case AF_INET6:
            addr = (char*)calloc(laddr = INET6_ADDRSTRLEN, sizeof(char));
            break;
    }

    if (laddr > 0)
    {
        inet_ntop(psa->sa_family, &((struct sockaddr_in*)(psa))->sin_addr, addr, laddr);
        rt.assign(addr);
        free(addr);
    }

    return rt;
}

std::string getIPAddr(const struct ifaddrs * pifa)
{
    std::string rt(pifa->ifa_name);
    if (pifa->ifa_addr)
        rt += " " + getSockToIP(pifa->ifa_addr);

    if (pifa->ifa_netmask)
        rt += " " + getSockToIP(pifa->ifa_netmask);

    return rt;
}

bool getIFAddrs(std::function<bool(struct ifaddrs * pifa)> cbFunc)
{
    struct ifaddrs * pifa = nullptr;
    if (getifaddrs(&pifa))
        return false;
    else
    {
        for (struct ifaddrs * p = pifa; !p; p = p->ifa_next)
            if (cbFunc(p))
                break;

        freeifaddrs(pifa);
        return true;
    }
}

void getIPs(std::function<std::string(void)> cbFunc)
{
    getIFAddrs([&](struct ifaddrs * pifa)
    {
//getIPAddr(pifa)
        return false;
    });
}

void getIP(const char * dev)
{
    getIFAddrs([&](struct ifaddrs * pifa)
    {
//getIPAddr(pifa)
        return !strcmp(pifa->ifa_name, dev);
    });
}



Последнее исправление: wolverin (всего исправлений: 1)

будет так работать не!?

void getIPs(std::function<void(std::string)> cbFunc)
{
    getIFAddrs([&](struct ifaddrs * pifa)
    {
        cbFunc(getIPAddr(pifa));
        return false;
    });
}

std::string getIP(const char * dev)
{
    std::string rt("");
    getIFAddrs([&](struct ifaddrs * pifa)
    {
        if (strcmp(pifa->ifa_name, dev))
            return false;
        else
        {
            rt.assign(getIPAddr(pifa));
            return true;
        }
    });
    return rt;
}
wolverin
() автор топика
Ответ на: комментарий от annulen

) сэкономить на строках кода с вызывающей стороны, переменные там не объявлять, не очищать

типа хочется получить просто без цикла функцию опрашиваешь и потом не заботишься за утечки.

wolverin
() автор топика
Ответ на: комментарий от wolverin

С std::vector<std::string> тоже никаких утечек не будет.

Коллбэк можно использовать для фильтрации, если нужно что-то более гибкое, чем сравнение с const char*. Это будет намного понятнее (и мб даже эффективнее), чем коллбэк с двумя задачами.

annulen 👍👍👍👍👍
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от ox55ff

) не все так просто, це на железку загрузить надо, уже завтра попробую

wolverin
() автор топика
Ответ на: комментарий от annulen

да это для примера контекст задачи попробовать решил не известную мне штуку ) вектор все равно чистить надо (а прежде объявлять), а тут просто стрингу в это лямбде вроде как должно отработать в одну строку, спасибо что вникли в мой говнокод )

wolverin
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Вектор сам себя чистит в деструкторе.

Да, я понимаю, что могут быть случаи, когда возвращать строки по одной через коллбэк будет удобнее, чем вектор - например, если потребитель это какой-то гуишный фреймворк, ожидающий добавление строк по одной. Но приведенные фрагменты сами по себе выглядят максимально искусственно. А ещё и неэффективно (из-за передачи объектов по значению вместо const& или &&), что как ножом по сердцу для любого плюсовика.

annulen 👍👍👍👍👍
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

если потребитель это какой-то гуишный фреймворк

)) да вам в битву экстрасенсов надо, в lvgl отправляю, еще не проверял на работоспособность, но ведь красивое!?

                    stringstream ss;
                    ss  << "Serial: " << pSys->getCPUinfo() << endl
                        << "STM: ver " << stmInfo.ver << " rev " << stmInfo.rev << endl
                        << "Hostname: " << pSys->getHostName() << endl
                        << "Network interfaces:\n";
                    pSys->getIPs([&](string dev) { ss << "\t" << dev << endl; });

                    FormShowServiceInfo(eFormType_t::SERVICE_INFO,
                            "Заголовок",
                            ss.str().c_str(),
                            "нижний колонтитул");

про ваше замечание это мне надо [&] заменить на [const&] ?

wolverin
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Будет. Проблемы начнутся, если он этот указатель куда-нибудь сохранит, например захватит в очередной лямбде. Раз у нас c++, то передавать нужно std::string, а не обмазываться сишкой и ходить по минному полю.

ox55ff 🤡🤡🤡🤡🤡
()

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

Возьмем например getSockToIP и пойдем по порядку, начиная с деталей. Почему в switch нет default на случай если в sa_family что-то иное? Зачем делать calloc на данные, которые затем будут скопированы в строку? Что если assign выкинет исключение? Где проверка на ошибки inet_ntop?

Добавим теперь чуть контекста. getSockToIP нужна только для getIPAddr. Каждый раз там будет делаться calloc, потом такая же аллокация в std::string, затем будет переаллоцироваться общий буфер, в который будут копироваться данные. Вместе с этим, все длины известны заранее. Все известно заранее, тебе нужно выделить одну единственную строчку и записать в нее все твои данные.

constexpr size_t addrstrlen(sa_family_t family) {
    switch (family) {
    case AF_INET:  return INET_ADDRSTRLEN;
    case AF_INET6: return INET6_ADDRSTRLEN;
    default:       throw std::logic_error{"addrstrlen: unknown family"};
}

std::string get_ip_addr(const struct ifaddrs& pifa) {
    char buf[max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) * 2 + 2];

    char* ptr = buf;
    if (pifa.ifa_addr) {
        *ptr++ = ' ';
        const size_t len = addrstrlen(pifa.ifa_addr->sa_family);
        if (!inet_ntop(pifa.ida_addr->sa_family, pifa.ifa_addr, ptr, len) {
            throw /* exception with errno */;
        }
        ptr += len;
    }

    /* аналогично для ifa_netmask */

    return { buf, ptr - buf };
}

и так далее.

Суть задачи проста - получить параметры одного или всех сетевых интерфейсов, понятно что можно в векторе, например, вернуть, но можно как то вот хитрожопо сделать через std::function или что то иное есть???

Суть задачи проста: сделать хитрожопо. Чем тебя не устроил вектор, зачем тебе std::function, что иное тебе нужно – неясно. Вместо того, чтобы постоянно гонять getifaddrs/freeifaddrs в exception-unsafe логике, лучше один раз их результаты (вернее их нужные части) сложить в вектор и спокойно обрабатывать далее.

Siborgium 👍
()
Последнее исправление: Siborgium (всего исправлений: 3)
Ответ на: комментарий от ox55ff

FormShowServiceInfo Сишная процедура, работающая с сишной библиотекой LVGL, поэтому никакого стринга там нет

wolverin
() автор топика
Ответ на: комментарий от Siborgium

addrstrlen

бл…

char buf[max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) * 2 + 2];

ёп..

Почему в switch нет default

потому шта пенадик не сказал мне что он прям очень необходим

wolverin
() автор топика

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

wolverin
() автор топика
Ответ на: комментарий от ox55ff

) ок, заменил stringstream просто на string + str.c_str()

зы. да знаю про что речь, но не актуально.

wolverin
() автор топика
Ответ на: комментарий от Siborgium

что было у пациента в голове, когда он его писал. Подозреваю впрочем, что было пусто – в сознание пациент не приходил.

«Мозга нет, но вес не изменился» (C) LEXX

seiken ☕☕☕☕☕
()
Ответ на: комментарий от Reset

большого размера

это что то на виндузятском

wolverin
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.