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)
Ответ на: комментарий от 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)
Ответ на: комментарий от Siborgium

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

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

seiken ★★★★★
()