C++ 如何创建具有预定义值和分配空间的字符串?

C++ 如何创建具有预定义值和分配空间的字符串?,c++,string,constructor,C++,String,Constructor,在C中,有一个很好的构造可以创建具有更多分配空间的C字符串: char str[6] = "Hi"; // [H,i,0,0,0,0] 我想我可以用(4)版的做同样的事情,但参考资料上说 如果s未指向至少包含图表计数元素的数组,则该行为未定义 所以使用起来不安全 std::string("Hi", 6); 有没有办法创建这样的std::string而不需要额外的拷贝和重新分配?理论: 遗留c字符串 考虑以下代码段: int x[10]; void method() { int

在C中,有一个很好的构造可以创建具有更多分配空间的C字符串:

char str[6] = "Hi";  // [H,i,0,0,0,0]
我想我可以用(4)版的做同样的事情,但参考资料上说

如果s未指向至少包含图表计数元素的数组,则该行为未定义

所以使用起来不安全

std::string("Hi", 6);

有没有办法创建这样的std::string而不需要额外的拷贝和重新分配?

理论:

遗留c字符串

考虑以下代码段:

int x[10];

void method() {
     int y[10];
}
第一个声明int x[10]使用static存储持续时间,由cppreference定义为:“当程序开始时分配对象的存储,当程序结束时解除分配对象的存储。只有一个对象实例存在。在命名空间范围(包括全局命名空间)声明的所有对象具有此存储持续时间,以及使用static或extern声明的存储持续时间。“

在这种情况下,分配在程序开始时发生,在程序结束时释放。发件人:

静态存储持续时间。对象的存储在程序开始时分配,在程序结束时解除分配

非正式地说,它是实现定义的。但是,由于这些字符串从不更改,它们存储在可执行文件的只读内存段(.BSS/.DATA)中,并且仅在运行时被引用

第二个,int y[10]使用自动存储持续时间,由cppreference定义为:“对象在封闭代码块的开头分配,在结尾取消分配。所有本地对象都有此存储持续时间,声明为static、extern或thread_local的对象除外。”

在本例中,有一个非常简单的分配,在大多数情况下,这个分配与移动堆栈指针一样简单

字符串

另一方面,
std::string
是一个运行时生物,它必须分配一些运行时内存:

  • 对于较小的字符串,std::string有一个大小恒定的内部缓冲区,并且能够存储小字符串(将其视为
    char buffer[N]
    成员)
  • 对于较大的字符串,它执行动态分配

练习

std::string str("Hi");
str.reserve(6);
您可以使用
reserve()
。此方法确保基础缓冲区至少可以容纳N个图表

选项1:先保留,然后追加

std::string str;
str.reserve(6);
str.append("Hi");
选项2:先构造,然后保留

std::string str("Hi");
str.reserve(6);

要确保最多一次运行时分配,您可以编写:

std::string str("Hi\0\0\0", 6);
str.resize(2);

但是,在实践中,许多字符串实现都使用了,如果字符串“短”(建议该线程上的大小不超过16),则不会进行分配。所以实际上,你不会因为从字符串的大小2开始,然后增加到6而遭受重新分配。

我知道,但是1)str被创建,2)str被重新分配到大小6,3)“Hi”被逐字节复制到str。我想避免这些步骤,只需创建[H,I,0,0,0,0]字符串。在第二个版本中,重新分配仍在发生。@JanTuroň-您似乎对
std::string
的工作原理有着根本性的误解。没有办法避免所有这些步骤。即使有一个托尔可以“一步到位”。它必须分配一个缓冲区,并复制您给它的文本。@StoryTeller-所以C版本中的静态分配也执行这些步骤?@JanTuroň-块范围?对虽然执行的分配要简单得多。@JanTuroň,但它取决于在何处声明
char str[6]
。它可以执行简单的
堆栈
分配(对于本地)或将其托管在.BSS/.DATA段中(对于静态/外部)。但是如果您想使用
std::string
会有某种分配(尽管字符串中有一个默认的最小块,可以用来为短字符串预留分配)
几乎肯定会分配2个以上的字符,这样,如果您只增加字符串的大小
6个
字符,您就不会支付重新分配的罚款。@Galik
std::string s=“Hi”;scanf(“%4s”和&s[2])-您能100%确定这不会导致分段错误吗?您问的是重新分配问题。无论您做什么,如果不调用未定义的行为,您将永远无法写入超出字符串的
size()
。所以,即使你可以做你想做的事情,你仍然不能
scanf(“%4s”,&s[2])。我只是指出,就再分配而言,字符串可能已经做出了相当明智的决定。