We have hierarchical messages that are represented by classes. They are used to send messages between threads and components by serializing/deserializing. In our use-case, we use std::variant<InnerA, InnherB, ...>
, but to simplify, our code is similar to this:
class Inner {
public:
Inner(uint8_t* array, uint16_t arrayLength) {
m_payloadLength = arrayLength; // Let's assume arrayLength is always < 256
memcpy(m_payload.data(), array, arrayLength));
}
std::array<uint8_t, 256> m_payload;
uint16_t m_payloadLength;
}
class Outer {
public:
Outer(const Inner& inner): m_inner(inner){};
Inner m_inner;
}
class OuterOuter {
public:
OuterOuter(const Outer& outer): m_outer(outer){};
Outer m_outer;
}
Thus to create an OuterOuter
object we need to do
int main(int argc, char** argv){
uint8_t buffer[4] = {1,2,3,4};
Inner inner(buffer, 4);
Outer outer(inner);
OuterOuter outerOuter(outer);
addToThreadQueue(outerOuter);
}
Now the thing is, we use an embedded device so we cannot use dynamic memory with malloc and new. As of now, will the payload content will be copied thrice? Once for the creation of inner, once when the copy constructor of Inner is called in Outer, and once when the copy constructor of Outer is called in OuterOuter? If so, is there a way to avoid all this copying without the use of dynamic memory? If there is a way to pass my intent to the compiler, may be an optimization would be possible, if it's not already optimizing it.
Ideally, we would avoid the OuterOuter
class taking all the subclasses construction argument since our tree is pretty deep and we use std::variant. In this example it would be OuterOuter(uint8_t* array, uint16_t arrayLength)
, Outer(uint8_t* array, uint16_t arrayLength)
and then Outer
would build Inner
.