Create a C style char** from a C++ vector I am dealing with some older C style APIs, like Posix execve that take a char**.  In the rest of my code, I prefer to use a fairly modern C++ style, so I have vector of std::string.  Is this the best way to handle the glue between them?

char ** strlist(std::vector&lt;std::string&gt; &amp;input) {
    char** result = new char*[input.size()];
    result[input.size()] = nullptr;
    for (int i=0; i&lt;input.size(); i++) {
        char *temp = new char[input[i].size()];
        strcpy(temp, input[i].c_str());
        result[i] = temp;
    }
    return result;
}


bool del_strlist(char ** strings, int limit=1024) {
    bool finished = false;
    for (int i=0; i&lt;limit; i++) {
        char *temp = strings[i];
        if (temp == nullptr) {
            finished = true;
            break;
        }
        delete temp;
    }
    delete strings;
    return !finished;
}
Since you already have a std::vector&lt;std::string&gt;, it's much simpler to let that own the memory, and build a parallel std::vector&lt;char*&gt; which just keeps pointers into the original strings. The only difficulty is ensuring this isn't used after the owning vector goes out of scope.

The simplest implementation is something like:

std::vector&lt;char*&gt; strlist(std::vector&lt;std::string&gt; &amp;input) {
    std::vector&lt;char*&gt; result;

    // remember the nullptr terminator
    result.reserve(input.size()+1);

    std::transform(begin(input), end(input),
                   std::back_inserter(result),
                   [](std::string &amp;s) { return s.data(); }
                  );
    result.push_back(nullptr);
    return result;
}


where the caller is responsible for managing the lifetimes of the two vectors. You get the required char ** by calling result.data().

If you want to avoid the potential lifetime problems, you can write a class to own both vectors for you so their lifetimes are synchronized.

Note that I deliberately haven't taken the vector by const ref, because execve takes an array of pointers to non-const char, but it doesn't mutate the contents so there's no need to make a copy. This lack of const-safety is common in old C interfaces.



PS. I didn't force myself to use transform when a simple loop would do hoping for some magic optimization. I used transform instead of a simple loop because it more clearly expressed the semantics of my code.

A "simple" loop is a powerful multipurpose language construct which could do anything. By comparison transform is a simple, special-purpose algorithm, and much easier to reason about as a consequence.

Not least, since I had to take a non-const reference to the argument despite having no intention of mutating it, anything that makes it easier to see at a glance that no mutation is possible, is helpful.