我可以在C++中从const char*数组中进行std::字符串的零拷贝分配吗

Can I do a zero-copy std::string allocation in C++ from a const char * array?

本文关键字:字符串 std 分配 拷贝 中从 C++ const char 数组 我可以      更新时间:2023-10-16

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

编辑:我正在处理二进制数据,所以我不能只传递char *s。此外,由于std::string避免了总是扫描NULL,我会有很大的开销。

如果字符串不会更改,并且它的寿命保证比您将要使用的字符串长,那么不要使用std::string

相反,考虑一个简单的C字符串包装器,如所提出的string_ref<T>

二进制数据?停止使用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会对缓冲区进行不必要的复制。

没有可移植的解决方案。如果你告诉我们你在使用什么工具链,有人可能知道你的库实现特有的技巧。但在大多数情况下,std::string析构函数(和赋值运算符)将释放字符串内容,而不能释放字符串文字。(这并非不可能有例外,事实上,小字符串优化是跳过释放的常见情况,但这些都是实现细节。)

当您不需要/不想要动态分配时,最好不要使用std::stringconst char*在现代C++中仍然运行良好。

由于C++17,std::string_view可能是您的选择。它既可以从裸C字符串(有或没有长度)初始化,也可以从std::string初始化

但是,data()方法返回一个以零结尾的字符串并没有任何约束。

如果你需要这种"请求时零终止"的行为,有其他选择,比如Adam Sawicki的str_view,看起来很令人满意(https://github.com/sawickiap/str_view)

似乎使用const char *而不是std::string是最好的方法。但您也应该考虑如何使用字符串。可能存在从字符指针到std::string对象的隐式转换。例如,这可能发生在函数调用期间。