使用char *构建动态结构的更好方法?

时间:2016-01-12 13:54:55

标签: c++ struct

我想使用C ++中的C风格的API,它采用可变数量的结构与char *成员,如下所示:

typedef struct _FOO
{
    const char * name;
    const char * value;
} FOO;

void ApiFunc(FOO const* args, unsigned count);

要填充参数,我需要循环其他一些数据并动态创建FOO条目。最优雅的方法是什么?

以下方法起初看起来很简单,但不起作用(因为字符串实例超出范围并在调用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() );

将字符串对象放在向量中(以防止它们被破坏)也不起作用 - 因为字符串在放入向量时被复制,而原始字符串仍然被破坏:

// 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() );

我可以通过在堆上创建字符串对象并使用auto_ptr来跟踪它们来防止这种情况,但是有更好的方法吗?

// 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() );

虽然方法C似乎有效,但我发现它相当不明显/难以理解。有什么建议我可以改进吗?

4 个答案:

答案 0 :(得分:4)

我很确定标准不允许std::vector<auto_ptr<T>>。请改用unique_ptr。或者,在向量中构建字符串,然后从中构建args。

std::vector<std::pair<std::string, std::string>> strings;
for (...)
{
     const std::string name = ...;
     const std::string value = ...;
     strings.push_back( std::make_pair( name, value ) );
}
// Note: This loop must be separate so that 'strings' will not reallocate and potentially
// invalidate the pointers returned by elements in it.
for (const auto& pair : strings)
{
    args.push_back( FOO{pair.first.c_str(), pair.second.c_str()} );
}

ApiFunc( args.data(), args.size() );

答案 1 :(得分:2)

由于您正在与C API接口,因此您将不得不采用C API方式。也就是说,分配堆缓冲区并在之后取消分配它们。这实际上是unique_ptr<T[]>

的实用程序的一个主要示例
//Helper function
std::unique_ptr<char[]> cpp_strdup(const std::string &str)
{
    std::unique_ptr<char[]> ret = new char[str.size() + 1];
    //Must copy the NUL terminator too.
    std::copy(str.data(), str.data() + str.size() + 1, ret.get());
    return ret;
}

//In your function:
std::vector<unique_ptr<char[]>> strings;

for (...)
{
   string name = ...   // something which gets
   strings.push_back(cpp_strdup(name));

   string value = ...  // calculated in the loop
   strings.push_back(cpp_strdup(value));

   args.push_back( FOO{strings[strings.size() - 2].get(), strings[strings.size() - 1].get()} );
}

unique_ptr向量中使用std::string代替strings,您可以在strings进行重新分配时自行避免重新分配字符串。

答案 2 :(得分:1)

您可以使用strdup功能。

string name = ...   // something which gets
string value = ...  // calculated in the loop
args.push_back( FOO{strdup(name.c_str()), strdup(value.c_str())} );

之后,您必须删除字符串。

free(foo.name);
free(foo.value);

答案 3 :(得分:0)

您可以使用存储在向量中的字符串:

   string name = ...   // something which gets
   string value = ...  // calculated in the loop
   strings.push_back( name );
   strings.push_back( value );
   args.push_back( FOO{strings[strings.size()-2].c_str(), strings[strings.size()-1].c_str()} );