使用 unique_ptr 的常量字符指针

Constant character pointer using unique_ptr

假设我有一个 vector<string> input,我需要将其传递给一个带有 const char** 参数的函数。我的想法是像这样使用 unique_ptr

const auto output = make_unique<char*>(size(input));

但我似乎无法将 const unique_ptr<const*> 变成 const char**。有没有办法做到这一点,或者更简单的替代方法?

我只想构建一个指向字符串 c_str() 的指针向量,然后获取指向它的指针。

std:vector<const char*> pointers;
pointers.reserve(input.size());
for (const auto& e : input)
    pointers.push_back(e.c_str()); // get const char *'s
auto argument = pointers.data(); // get pointer to const char*'s - const char**

或使用 unique_ptr

auto pointers = std::make_unique<const char*[]>(size(input))
for (size_t i = 0; i < input.size(); ++i)
    pointers[i]= input[i].c_str(); // get const char *'s
auto argument = pointers.get(); // get pointer to const char*'s - const char**

我假设你需要这个来适应一些你无法控制的界面,否则我会考虑调整有问题的界面以避免为了适应一个不合适的界面而不必要地创建临时数据…

由于您只需要一个已知大小的临时数组,最简单的解决方案可能是分配一个指针数组并用指向向量中的字符串的指针填充它:

auto pointers = std::make_unique<const char*[]>(size(v));
std::transform(begin(v), end(v), &pointers[0], [](const auto& s) { return s.c_str(); });

这个数组也可以放在栈上以避免动态内存分配。但由于您在这里使用字符串并愿意将数据复制到临时数组中,我认为性能并不重要,所以我想没有必要增加复杂性……

两种方法,取决于 c 接口是否需要空终止:

#include <vector>
#include <string>
#include <algorithm>

auto make_c_interface_null_terminated(std::vector<std::string> const &input) -> std::vector<const char*>
{
    auto result = std::vector<const char*>(input.size() + 1);
    auto to_c_str = [](auto&& str) { return str.c_str(); };
    std::transform(begin(input), end(input), begin(result), to_c_str);
    // implied:  result[result.size() - 1] = nullptr
    return result;
}

auto make_c_interface(std::vector<std::string> const &input) -> std::vector<const char*>
{
    auto result = std::vector<const char*>(input.size());
    auto to_c_str = [](auto&& str) { return str.c_str(); };
    std::transform(begin(input), end(input), begin(result), to_c_str);
    return result;
}


extern "C" void c_interface_requires_null(const char** argv);
extern "C" void c_interface_sized(size_t size, const char** args);


void test(std::vector<std::string> const &input)
{
    auto output1 = make_c_interface_null_terminated(input);
    c_interface_requires_null(output1.data());

    auto output2 = make_c_interface(input);
    c_interface_sized(output1.size(), output1.data());
}