字符串未针对字符串文字进行优化

时间:2011-12-05 13:13:33

标签: c++ string stl

在我的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*构造它时,它不是。我的问题是:为什么会这样?我错过了什么吗?我的标准库是不是足够优化还是出于某些原因(我不知道)这完全不安全?

3 个答案:

答案 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*