Проблема с WifiClient - должна быть основной проблемой C / C ++ в отношении локальных и глобальных переменных - PullRequest
0 голосов
/ 17 марта 2019

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

Я не думаю, что есть большая необходимость знать базовые библиотеки.

Должна быть тонкость, связанная с указателями / сборкой мусора или чем-то, что не является причиной этого.Я занимался C # годами, у меня гораздо меньше опыта работы с C ++.

#include <PubSubClient.h>
#include <WiFiClient.h>

void mqttSubs(char* topic, byte* payload, unsigned int length) {}   


// if this line is moved inside setup() then the call to publish will crash
WiFiClient wifiClientGlobal;
PubSubClient mqttClient;

void setup() {
  //WiFiClient wifiClientGlobal;
  mqttClient = PubSubClient(mqttServer, mqttPort, mqttSubs, wifiClientGlobal);
  mqttClient.connect("ESP8266Client", mqttUser, mqttPassword );
}

void loop() {
  mqttClient.publish("repro/global", "sending message");
}

Может кто-нибудь пролить свет на это?

1 Ответ

1 голос
/ 17 марта 2019

В PubSubClient не так много субтитров, просто (imo) плохая документация и неоптимальный API.

Конструктор PubSubClient получает ссылку на клиента.

PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);

И затем получает указательсохранить его как член.

Это означает, что он ожидает экземпляр Client, на который он ссылается, чтобы пережить экземпляр PubSubClient.

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

Так что причина по сути такова:

struct B{
    int num;
};

struct A{
    A(B& param){
        m_b = &param;
    }
    B* m_b;
};

A obj;

setup()
{
    B b;
    obj = A(b); 
    //after this function ends b is considered destroyed
}

loop()
{
    //the following line accesses a member of the already destroyed object
    print(obj.m_b->num);
}

Этот тестовый пример демонстрируетпо сути то же самое «использование после освобождения», что и в вашем коде (он, вероятно, не будет аварийно завершать работу, но он будет содержать то же неопределенное поведение).

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

...