对我的应用程序的分析显示,它在字符串分配上花费了近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::string
。const 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
对象的隐式转换。例如,这可能发生在函数调用期间。