Search code examples
c++c++14smart-pointers

Customize the deleter to deallocate a 2D array through std::unique_ptr


Suppose I am parsing an environment variable list from a given map<string, string> to a 2D memory held by unique_ptr<char*[]>. However, I am not sure how I can customise the deleter for this 2D memory case ?

// Given: env (type of map<string, string>)
// Return: unique_ptr<char*[]> (with customized deleter)

// Prepare for parsing the environment to c-style strings
auto idx = size_t{0};

// What should I fill for `ret` a proper deleter that won't give memory leak?
auto ret = std::make_unique<char*[]>(env.size() + 1, ???);   
for(const auto& kvp : env) {
  auto entry = kvp.first + "=" + kvp.second;
  ret[idx] = new char[entry.size() + 1]; 
  strncpy(ret[idx], entry.c_str(), entry.size() + 1); 
  ++idx;
}
ret[idx] = nullptr;  // For the later use of exec call

return ret;

Apparently, the above code leaks, because of the new operator in the inner for loop.


Solution

  • There is no version of std::make_unique accepting a deleter as argument (by the way, std::make_unique is C++14, not C++11). Try this:

    size_t size = env.size() + 1;
    
    auto ret = std::unique_ptr<char*, std::function<void(char**)> >(
        new char* [size],
        [size](char** ptr)
        {
            for(size_t i(0); i < size; ++i)
            {
                delete[] ptr[i];
            }
            delete[] ptr;
        }
    );
    

    You can pass ret.get() to execvpe.