TL;DR: create a Queue of pointers to std::string
and handle new
/delete
on either side. Make sure both producer and consumer are using a shared memory space.
The problem with using std::string
in a "raw" memory API like FreeRTOS Queue
isn't actually an issue with the size of the object. In fact the std::string
object size is fixed, regardless of the size of the character array stored by the object. Don't believe me? Try compiling and running this simple program on your own machine:
#include <iostream>
int main(int argc, char **argv)
{
std::string str1 = "short";
std::string str2 = "very very very very very very long";
std::cout << "str1 length = " << sizeof(str1) << "\n";
std::cout << "str2 length = " << sizeof(str2) << "\n";
return 0;
}
You'll get something like this (actual size will vary depending on your platform):
str1 length = 24
str2 length = 24
Note that this result would be different if you used str1.size()
.
The reason for this is that standard library containers like std::string
usually store their contents in malloc'ed blocks, so the std::string
object itself will just store a pointer to an array that contains the character data in the string. The sizeof()
in this case tells you the size of the object from the compiler's perspective, which would be the size of the pointer and other fixed metadata (i.e. the fields of the struct). The .size()
method tells you the size of the string from the implementation, which will include a string length calculation on the allocated character array.
The reason you can't just copy a std::string
object into the xQueueSend()
variants is a problem of lifecycle management. The FreeRTOS API does *Send
and *Receive
via raw memcpy
. Standard library containers are usually not POD types, which means they must be copied via a dedicated copy constructor. If you don't do this, you're likely to invalidate some internal state of the object unless you really know what you're doing.
So the easiest way to make this work would look something like this:
- On
xQueueCreate()
, set your object size to sizeof(std::string *)
:
xQueue = xQueueCreate(NUM_OBJECTS, sizeof(std::string *));
- On
xQueueSend()
, create a std::string
via operator new
, and pass an address to this pointer to be copied. Do not delete the object.
std::string *pStr = new std::string("hello world!");
xQueueSend(xQueue, &pStr, (TickType_t)0);
- On
xQueueReceive()
, copy out the pointer. Do what you need to do with this pointer, and then delete
it.
std::string *pStr = NULL;
xQueueReceive(xQueue, &pStr, (TickType_t)10);
// do stuff with pStr
delete pStr;