2015-09-05 78 views
7

我知道下面的代码将创建一个字符数组,并保持在内存中,直到节目结束:分配一个字串的std :: string

char* str = "this is a string"; 

对于这一说法,创建一个本地阵列字符,将被释放时,STR超出范围:

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

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

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

str应该在自己的内存(本地)中创建一个字符串的副本,但是字符串本身又如何呢?它是否具有程序的生命周期,或者当str超出范围时它将被释放?

+5

字符串文字具有“静态”存储持续时间,所以它**总是**在程序的整个生命周期中都存在。 –

+0

'std :: basic_string'不拥有文字,因此它的生存期不是由'str'确定的。 – edmz

回答

6

当你写这个

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的构造函数,并忘记它。允许优化器消除所有字符串文字中的重复项,包括仅在其他对象的初始化中使用的重复项。

+7

IIRC,在这里可以不调用'operator =',因为这需要在两边都构建一个对象。相反,用'='初始化调用复制构造函数。 – Oberon

+0

@Oberon你是对的,它是一个复制构造函数。我确定了答案,非常感谢! – dasblinkenlight

0

一些你最初的陈述是不完全正确的:

对于char *char []例如,在两种情况下,变量本身,str仍然在范围和访问,直到它是否在全局命名空间被声明的程序结束。

如果它在函数或方法的作用域中声明,那么在范围保持活动状态时它是可访问的。两个都。

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

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

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

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

但是请注意,除了范围问题外,std::string对象的一些方法(但并非全部)也被指定为使所有现有的直接指针和迭代器都无效到其内容,因此这也会影响是否a将char *指定给std::string中的其中一个字符仍然有效。

3

大多数操作系统将划分您的程序内存分为几个部分

  • 堆栈
  • 的堆
  • 数据段
  • BSS段
  • 代码段

你已经知道堆栈和堆,但那其他人呢?

代码段保持二进制形式的所有操作。

现在它变得有趣: 让我们来看看下面的代码:

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

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

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

BSS段是数据段的一个子集,它保留全局指针和静态指针,这些指针是null-intitalized的。

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

现在怎么办 std::string str = "hello world";

这是一个时髦的情况。 str本身生活在堆栈上。实际的内部缓冲区位于堆上,但用于分配字符串的字符串字面值存在于数据段中,并且代码段中生存的代码值为hello world。不用说,如果我们要组装程序,我们需要用我们自己的手来构建这个生态系统。

0

我会提供一个柜台问题:你为什么在意?

的C++标准规定,当涉及到的实现基本上是被称为AS-如果规则语言的行为,和第一核心原则:

§1.9程序执行

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


你的情况:

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

有各种有效的方案:

  • 你不使用str之后?那么这整个代码部分可能会完全消失
  • 您以后立即将'T'分配给str[0]?那么这两个可能会被合并为std::string str = "This is a string";
  • ...

,并没有保证,以什么编译器会做。它可能取决于你使用的编译器,你使用的标准库实现,你正在编译的体系结构/操作系统,甚至是传递给编译器的参数......

因此,如果你想知道你的案例中的,您将不得不检查生成的机器码。问coliru,为以下代码:

#include <string> 

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

锵产生在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"将在二进制中是原样并将被加载到只读存储器中。它将留在进程的地址空间中,直到结束,操作系统可能会根据内存压力将其分页或不分页。

相关问题