I want to use a C-style API from C++ which takes a variable number of structs with char* members like this:
typedef struct _FOO
{
const char * name;
const char * value;
} FOO;
void ApiFunc(FOO const* args, unsigned count);
To fill the parameters, I need to loop over some other data and create FOO entries on the fly. What would be the most elegant way to do that?
The following approach seems simple at first, but does not work (since the string instances go out of scope and are destroyed before the call to ApiFunc()):
// Approach A: this does *not* work
std::vector<FOO> args;
for (...)
{
string name = ... // something which gets
string value = ... // calculated in the loop
args.push_back( FOO{name.c_str(), value.c_str()} );
}
ApiFunc( args.data(), args.size() );
Putting the string objects in a vector (to prevent them from being destroyed) doesn't work either - as the strings are copied when put into the vector, and the original ones are still destroyed:
// Approach B: this also does *not* work
std::vector<string> strings;
for (...)
{
string name = ... // something which gets
string value = ... // calculated in the loop
strings.push_back( name );
strings.push_back( value );
args.push_back( FOO{name.c_str(), value.c_str()} );
}
ApiFunc( args.data(), args.size() );
I can prevent that by creating the string objects on the heap and using auto_ptr to keep track of them, but is there a better way?
// Approach C: this does work
std::vector<auto_ptr<string>> strings;
for (...)
{
string* name = new ...
string* value = new ...
strings.push_back( auto_ptr<string>(name) );
strings.push_back( value );
args.push_back( FOO{name.c_str(), value.c_str()} );
}
ApiFunc( args.data(), args.size() );
While approach C. seems to work, I find it rather unobvious / hard to understand. Any suggestions how I could improve it?