Values stored via standard Map lib gets corrupted from time to time

Hi.

I like to store a hash of the last message avoiding duplicate messages send by my MQTT project. I like to use a dictionary created via lib. Actually I store the char array for testing and facing the behavior that the char array stored gets corrupted from time to time.

My debugging output looks like this with random symbols but it should show the same string twice:

----------
08:45:44
wifi
1
�Q�?␔␘�?(A�?␟
{"ssid":"I-Gate","sta_ip":"192.168.177.26","rssi":-78,"mac":"7C:9E:BD:39:67:6C"}
0
----------

I implemented it like this and during most runs it works fine but round about every 5 to 10 minutes the char array is broken.

std::map<const char *, const char *> mqttLastMessage;

void mqttPublish(const char *topic, const char *payload, bool force)
{
  String tempTopic;
  tempTopic += mqttTopicPath;
  tempTopic += topic;

  Serial.println("----------");
  Serial.println(timeClient.getFormattedTime());
  Serial.println(topic);

  if (mqttLastMessage.find(topic) == mqttLastMessage.end())
  {
    mqttLastMessage[topic] = payload;
    Serial.println("Topic initalisiert");
  }
  if (mqttClient.connected())
  {
    Serial.println(strcmp(mqttLastMessage[topic], payload) != 0);
    Serial.println(mqttLastMessage[topic]);
    Serial.println(payload);
    Serial.println(force);
    Serial.println("----------");
    if (strcmp(mqttLastMessage[topic], payload) != 0 || force)
    {
      mqttClient.publish(tempTopic.c_str(), 0, true, payload);
      mqttLastMessage[topic] = payload;
    }
  }
  else
  {
    Serial.print("mqtt message could not be send: ");
    Serial.print(tempTopic.c_str());
    Serial.print(" = ");
    Serial.println(payload);
  }
}

There is no interaction with mqttLastMessage outside the function. Does anybody knows what could be the problem?

Also I am not sure if I should check for existence as it runs without the same way.

Cheers,
Nils

You didn't post a complete code, so I can only supply an incomplete answer. I'm guessing it's because you don't actually store the data in your std::map, you just store a pointer to it. I'd say the memory being pointed to is later deallocated, reused, or otherwise becomes invalid.

1 Like

The whole code is available here: ImpulseSmartMeter/src/main.cpp at 201c888bdec5c533dfdfa06afa97b5039d24f62f · NilsRo/ImpulseSmartMeter · GitHub

I tried to use strcpy but it fails using map. Do you have a hint how to copy the content into the dictionary?

I won't be clicking on a random link of unknown provenance. Post the code here, in-line, with code tags.

Also tell us exactly which Arduino board you're compiling for, which version of the Arduino Core for that board, and exactly which versions of libraries you're using.

Maybe
std::map<const String, const String> mqttLastMessage;

and
mqttLastMessage.emplace(topic, payload);

EDIT:
BTW, you don't need to use find() to see if topic is already in the map. The emplace() function will do that for you and only add to the map if the topic doesn't already exist.

I ask ChatGPT and it give me the technical correct answer. With str::map only types can be used that are comparable via ==,.. . This is not the case for a char array. I use now std::map<const String, const String> and it seems working fine.

Is it not possible to supply your own function for the comparison?

I only read a little bit about std::map, wandered in here wondering how the map() I know could go wrong. :expressionless:

a7

Yes:

#include <map>

struct CstringCompare {
  bool operator() (const char *lhs, const char *rhs) const {
    return (strcmp(lhs, rhs) < 0);
  }
};
std::map<const char *, const char *, CstringCompare> mqttLastMessage;

But it doesn't solve OP's other problem:

Yes, thanks.

Let me figure out how it worked at all, given the "solution" and this other part of the problem…

I marvel at what must all be happening with std::map, looks very handy and expensive.

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.