【问题标题】:Fill std::string directly from C API直接从 C API 填充 std::string
【发布时间】:2017-10-21 19:52:40
【问题描述】:

我发现自己经常围绕 C 风格的 API 编写 c++ 包装器,而且我编写的一些常见的浪费代码是这样的:

//getSomeString() wraps C api that gets some C string from somewhere
std::string MyClass::getSomeString()
{
    char buffer[BUFFER_MAX];
    memset(buffer, '\0', BUFFER_MAX);
    auto result = GetCApiString(buffer, BUFFER_MAX); //C style string getter 
    return (result == NO_ERROR) ? std::string{buffer} : ""; //Copy here
}

但我真的很想做这样的事情:

//getSomeString(): as before
std::string MyClass::getSomeString()
{
    DirectStringFillIterator<char> returnString; // <--HERE. Is something like this possible?
    auto result = GetCApiString(returnString, BUFFER_MAX);
    return (result == NO_ERROR) ? returnString.str() : ""; 
}

这样的事情可能吗?

【问题讨论】:

  • 如果您要包装返回 NULL 的 C 代码,通常最好将 C 错误映射到 C++ 异常。这避免了必须返回垃圾空字符串。在 Rust 或 Swift 等其他语言中,您可以将结果封装为“可选”,您可以在其中测试它是否包含值,但 C++ 对此类概念确实不那么开放。
  • @tadman - 未打开?有boost::optional。很快就会在这里std::optional
  • @StoryTeller 哦,很高兴看到。我的意思是“开放”,就像 Swift 的隐式展开语义中的 !。也许“理想”是一个更好的词。
  • @Jodocus:这将如何解决任何问题?如果你有一个本地缓冲区返回一个 string_view 给它只会打开未定义行为的大门......

标签: c++ c++11 c++14 c++17


【解决方案1】:

std::string 自 C++11 以来保证是连续的(但即使在 C++03 中,我遇到的每个实现都是如此)。所以,通常你可以这样做

std::string MyClass::getSomeString() {
    std::string ret(BUFFER_MAX, '\0');
    if(GetCApiString(&ret[0], ret.size()) != NO_ERROR) return "";
    ret.resize(ret.find_first_of(0));
    return ret;
}

这避免了对第一个方法的复制(从本地缓冲区到返回的字符串),但强制返回的字符串始终分配 BUFFER_MAX 字节,这在您的情况下可能是也可能不是缺点。

【讨论】:

  • 哦,那太好了。非常简单的想法,我忽略了。感谢您的回答,我会尽快将其标记为已解决。
  • 比起&amp;ret[0],我个人更喜欢ret.data()
  • @MatteoItalia 在 C++17 中将添加一个新的非const 重载(用于.data(),而不是.c_str())。
  • 没有 std::string 构造函数只是计数,至少也需要传递一个字符,例如std::string ret(BUFFER_MAX, '\0')
  • @HolyBlackCat:好吧,这更尴尬,这是一个脑残,但导致了一个微妙的逻辑错误;我希望使用此代码的人在复制粘贴之前费心实际检查结果...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多