简体   繁体   English

WifiClient问题-必须是有关局部变量和全局变量的基本C / C ++问题

[英]WifiClient issue - must be a basic C/C++ problem regarding local vs. global variables

In the code below, I am getting crashes when doing mqtt.publish() but this only happens if wificlient is a local variable - the issue goes away if wificlient is a global variable. 在下面的代码中,执行mqtt.publish()时会崩溃,但这仅在wificlient是局部变量的情况下才会发生-如果wificlient是全局变量,则问题就消失了。

I don't think there's much of a need to know the underlying libraries. 我认为并不需要了解底层库。

There must be a subtlety regarding pointers / garbage collection or what not that causes this. 关于指针/垃圾回收必须有一些细微之处,否则会导致这种情况。 I've been doing C# for years, have much less experience with C++. 我已经从事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");
}

Can anyone shed a light on this? 谁能阐明这一点?

There's not much sublety, just (imo) bad documentation and suboptiomal API on PubSubClient. 没有太多的转租,只是(imo)错误的文档和PubSubClient上的优化API。

The PubSubClient constructor takes a reference to the client. PubSubClient构造函数采用对客户端的引用。

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

And then takes a pointer to it to store as a member. 然后获取指向它的指针以将其存储为成员。

This means that it expects the Client instance it takes a reference to to outlive the PubSubClient instance. 这意味着它希望引用的Client实例的PubSubClient超过PubSubClient实例的PubSubClient

There's no garbage collection taking place. 没有垃圾收集发生。 It's just that if you declare an object with automatic storage duration then it will be destroyed when it goes out of scope. 只是如果您声明一个具有自动存储持续时间的对象,那么当它超出范围时,它将被销毁。

So the reason is essentially this: 因此,原因基本上是这样的:

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);
}

This test case exhibits essentially the same "use after free" as your code (it probably won't crash but it does contain the same undefined behavior). 这个测试用例表现出与您的代码基本相同的“免费使用后使用”(它可能不会崩溃,但确实包含相同的未定义行为)。

The PubSubClient taking a reference to the client and storing the pointer for later use is a bad pattern in my opinion. 在我看来, PubSubClient获取对客户端的引用并存储指针以供以后使用是一种错误的模式。 It should take a pointer to the client to make it more apparent that this is what happens. 它应该使用指向客户端的指针,以使其更清楚地了解发生了这种情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM