在我的C ++项目中,我在用char*
替换所有std::string
之前迈出了一步,但我找到了std::string
失败的某个特定场合。
想象一下,我有这两个功能:
void foo1(const std::string& s)
{
...
}
void foo2(const char* s)
{
...
}
如果我写这样的话:
const char* SL = "Hello to all!";
foo1(SL); // calls malloc, memcpy, free
foo2(SL);
<{1>} foo1
SL
将隐式转换为std::string
。这意味着std::string
构造函数将分配内存,并将字符串文字复制到该缓冲区。在foo2
中,尽管所有这些都不会发生。
在大多数实现中,std::string
应该是超级优化的(例如Copy On Write),但是当我用const char*
构造它时,它不是。我的问题是:为什么会这样?我错过了什么吗?我的标准库是不是足够优化还是出于某些原因(我不知道)这完全不安全?
答案 0 :(得分:21)
实际上,如果你更改了文字,你的担忧就会消失(*):
std::string const SL = "Hello to all!";
我为你添加了const
。
现在,调用foo1
不会涉及任何复制(根本不会),并且可以少付费用调用foo2
:
foo1(SL); // by const-reference, exact same cost than a pointer
foo2(SL.c_str()); // simple pointer
如果你想转移到std::string
,不仅要切换功能接口,还要切换变量(和常量)。
(*)原始答案假设SL
是一个全局常量,如果它是函数的局部变量,那么如果真的希望避免在static
构建它,可以使它成为{{1}}每次通话。
答案 1 :(得分:10)
问题是std :: string类无法识别const char*
指针是否是全局字符文字:
const char *a = "Hello World";
const char *b = new char[20];
char *指针可能在任何时候都无效(例如,当它是局部变量且函数/范围结束时),因此std::string
必须成为字符串的独占所有者。这只能通过复制来实现。
以下示例说明了为什么有必要:
std::string getHelloWorld() {
char *hello = new char[64];
strcpy(hello, "Hello World");
std::string result = (const char *)hello; // If std::string didn't make a copy, the result could be a garbage
delete[] hello;
return result;
}
答案 2 :(得分:5)
std::string
不是灵丹妙药。它旨在成为拥有其内存的通用可变字符串的最佳实现,并且使用C API相当便宜。这些是常见的情况,但它们与每个字符串用法实例都不匹配。
正如您所提到的,字符串文字不适合这个用例。它们使用静态分配的内存,因此std::string
不能也不应该尝试获取内存的所有权。这些字符串总是只读,因此std::string
不允许您修改它们。
std::string
创建传递给它的字符串数据的副本,然后在内部处理此副本。
如果你想对其生命周期在其他地方处理的常量字符串进行操作(在字符串文字的情况下,它由初始化和释放静态数据的运行时库处理),那么你可能想要使用不同的字符串表示。也许只是一个简单的const char*
。