我可以从const char *数组中用C ++进行零拷贝std :: string分配吗?

时间:2012-10-08 16:28:41

标签: c++ performance stdstring zero-copy

我的应用程序的分析表明它在字符串分配中占用了近5%的CPU时间。在许多地方,我从64MB字符缓冲区制作C ++ std :: string对象。问题是,缓冲区在程序运行期间永远不会改变。我对std::string(const char *buf,size_t buflen)调用的分析是正在复制字符串,因为缓冲区可能在字符串生成后发生变化。这不是问题所在。有没有解决这个问题的方法?

编辑:我正在使用二进制数据,所以我不能只传递char *s。此外,我总是会在扫描NULL时遇到很大的开销,std::string会避免这种情况。

5 个答案:

答案 0 :(得分:7)

如果字符串不会改变,并且保证其生命周期长于您要使用字符串,则不要使用std::string

相反,请考虑一个简单的C字符串包装器,就像建议的string_ref<T>

一样

答案 1 :(得分:3)

没有便携式解决方案。如果你告诉我们你正在使用什么工具链,有人可能会知道一个特定于你的库实现的技巧。但是在大多数情况下,std::string析构函数(和赋值运算符)将释放字符串内容,并且您无法释放字符串文字。 (对此有例外并非不可能,实际上小字符串优化是跳过解除分配的常见情况,但这些是实现细节。)

更好的方法是在不需要/想要动态分配时不使用std::stringconst char*在现代C ++中仍然可以正常工作。

答案 2 :(得分:3)

二进制数据?停止使用std :: string并使用std::vector<char>。但这不会解决你被复制的问题。根据您的描述,如果这个巨大的64MB缓冲区永远不会改变,那么您真的不应该使用std :: string或std::vector<char>,任何一个都不是一个好主意。你真的应该传递一个const char *指针(const uint8_t *会更多地描述二进制数据,但是在掩护下它是同样的事情,忽略了符号问题)。传递指针和size_t长度,或者用另一个'end'指针传递指针。如果您不喜欢传递单独的离散变量(指针和缓冲区的长度),请创建一个描述缓冲区和结构的结构。让每个人都使用这些:

struct binbuf_desc {
    uint8_t* addr;
    size_t len;
    binbuf_desc(addr,len) : addr(addr), len(len) {}
}

您始终可以使用binbuf_desc个对象来引用64MB缓冲区(或任何其他任何大小的缓冲区)。请注意,binbuf_desc对象不拥有缓冲区(或它的副本),它们只是它的描述符,因此您可以在任何地方传递它们,而不必担心binbuf_desc正在制作不必要的缓冲区副本。

答案 3 :(得分:1)

由于C ++ 17,std::string_view可能是您的选择。可以从裸C字符串(具有或不具有长度)或std::string

对其进行初始化。

尽管没有限制,但data()方法返回的字符串以零结尾。

如果您需要这种“按要求零终止”的行为,那么亚当·萨维奇(Adam Sawicki)的str_view这样的替代方案看起来就很令人满意(https://github.com/sawickiap/str_view

答案 4 :(得分:0)

似乎使用const char *代替std::string是最适合您的方式。但是你也应该考虑如何使用字符串。可能会有从char指针到std::string对象的隐式转换。例如,在函数调用期间可能会发生这种情况。