将字符串文字分配给std :: string

时间:2015-09-05 13:38:29

标签: c++ string const

我知道以下代码将创建一个字符数组并保留在内存中,直到程序结束:

char* str = "this is a string";

对于这个语句,创建一个本地字符数组,当str超出范围时将被释放:

char str[] = "this is a string";

我很好奇的是,当我这样写时会发生什么:

std::string str = "this is a string";

str应该在它自己的内存(本地)中复制字符串,但字符串文字本身呢?它是否具有程序的生命周期,或者当str超出范围时是否会被释放?

4 个答案:

答案 0 :(得分:7)

当你写这个

std::string str = "this is a string";

C ++应该找到std::string的构造函数,它接受const char*,调用它来创建一个临时对象,调用复制构造函数将该临时文件复制到str,然后销毁临时对象对象

但是,有一个优化允许C ++编译器跳过临时对象的构造和销毁,因此结果与

相同
std::string str("this is a string");
  

但字符串文字本身呢?它是否具有程序的生命周期,或者当str超出范围时是否会被释放?

程序无法访问以这种方式使用的字符串文字本身。通常,C ++将它放在与其他字符串文字相同的段中,使用它传递给std::string的构造函数,并忘记它。允许优化器消除所有字符串文字中的重复项,包括仅在初始化其他对象时使用的字符串文字。

答案 1 :(得分:4)

大多数操作系统会将程序内存分成几个部分

  • The Stack
  • The Heap
  • 数据段
  • BSS段
  • 代码段

你已经知道堆栈和堆了,但其他的呢?

代码段以二进制形式保存所有操作。

现在它变得有趣: 让我们看一下以下代码:

int x;
class Y{  static int y;  };
int main(){
  printf("hello world");
  return 0;
}

程序在哪里分配xy?它们不是本地的或动态分配的,所以在哪里?

数据段保留所有静态和全局变量,在加载程序时,这些段保留足够的字节来保存所有静态和全局变量。如果变量是一个对象,当程序运行时它会为所有变量分配足够的字节,包括对象。在main程序调用每个全局对象构造函数之前,在main完成之后,它以相反的顺序调用每个对象析构函数,它调用构造函数。

BSS段是数据段的一个子集,它保存全局和静态指针,这些指针是空的。

因此,假设字符串文字未被优化,程序将其存储在数据段中。只要程序存在,它就会继续存在。而且,如果它是一个字符串文字,很可能你甚至可以在exe中看到它!将exe作为文本文件打开。沿途有一点,你会清楚地看到字符串。

现在呢 std::string str = "hello world";

这是一个时髦的情况。 str本身就存在于堆栈中。实际的内部缓冲区存在于堆上,但用于分配字符串的字符串文字存在于数据段中,而使str值变为hello world的代码存在于代码段中。不用说,如果我们要在集会中进行计划,我们就需要用自己的双手建立这个生态系统。

答案 2 :(得分:0)

您的一些初步陈述不太正确:

对于char *char []示例,在两种情况下,变量本身str都保留在范围内,并且如果程序在全局名称空间中声明,则可以访问它

如果在功能或方法的范围内声明,则在范围保持活动状态时可以访问它。他们两个。

对于用于存储实际文字字符串的内存实际发生的情况,这是未指定的。只要结果符合C ++标准,特定的C ++实现就可以以更方便的方式管理运行时内存。就C ++而言,您没有访问str对象使用的内存,而您只是引用str对象本身。

当然,您可以自由地使用本地char *指针,指向str中的一个字符。但是指针是否有效直接与底层对象的范围相关联。当相应的str对象超出范围时,指针不再有效,并且访问指针的内容将变为未定义的行为。

请注意,在str位于全局命名空间的情况下,str的范围是程序的生命周期,因此这一点没有实际意义。但是当str在本地范围内,并且它超出范围时,使用指针将变为未定义的行为。底层内存发生的事情是无关紧要的。 C ++标准并没有真正定义底层实现中应该或不应该发生什么内存,但是什么是未定义的行为。

基于此,你几乎可以自己找出std::string案例的答案。这是一回事。您正在访问std::string对象,而不是底层内存,并且适用相同的原则。

但请注意,除了作用域问题之外,std::string对象的一些(但不是全部)方法也被指定为使所有现有的直接指针和迭代器与其内容无效,因此这也会影响是否或者char *中某个字符的直接std::string仍然有效。

答案 3 :(得分:0)

我会提出一个反问题:你为什么关心?

C ++标准规定了语言的行为,实现时的第一个核心原则基本上称为as-if规则:

  

§1.9程序执行

     

1 / 本国际标准中的语义描述定义了参数化的非确定性抽象机器。本国际标准对符合实施的结构没有要求。特别是,它们不需要复制或模拟抽象机器的结构。相反,需要符合实现来模拟(仅)抽象机器的可观察行为,如下所述。

在你的情况下:

std::string str = "this is a string";

有各种有效的方案:

  • 之后您没有使用str?然后可以完全省略整个代码部分
  • 之后您立即将'T'分配给str[0]?然后两者可能合并为std::string str = "This is a string";
  • ...

并且无法保证您的编译器将执行的操作。它可能取决于您使用的编译器,您使用的标准库实现,您正在编译的体系结构/ OS,甚至传递给编译器的参数......

因此,如果您想了解 ,则必须检查生成的机器代码。询问coliru,代码如下:

#include <string>

int main(int argc, char** argv) {
    std::string str = "this is a string";
}

Clang在IR中产生以下内容:

@.str = private unnamed_addr constant [17 x i8] c"this is a string\00", align 1

反过来提供以下程序集:

.L.str:
    .asciz    "this is a string"
    .size .L.str, 17

所以你拥有它,对于这些特定条件,"this is a string"将在二进制文件中按原样加载,并将加载到只读内存中。它将保留在进程的地址空间中,直到结束,操作系统可能会根据RAM压力将其分页或不分页。