C++中的字符串常量存在多长时间?

10
我一直在想,在C++中,字符串常量存活的时间有多长。例如,如果我在函数内部创建了一些 const char *str = "something" ,返回 str 的值是否安全呢?
我编写了一个示例程序,并非常惊讶地发现,所返回的值仍然存储着那个字符串。以下是代码:
#include <iostream>
using namespace std;

const char *func1()
{
    const char *c = "I am a string too";
    return c;
}

void func2(const char *c = "I'm a default string")
{
    cout << c << endl;
}

const int *func3()
{
    const int &b = 10;
    return &b;
}

int main()
{
    const char *c = "I'm a string";
    cout << c << endl;
    cout << func1() << endl;
    func2();
    func2("I'm not a default string");
    cout << *func3() << endl;
    return 0;
}

它给我以下输出:

我是一个字符串

我也是一个字符串

我是一个默认字符串

我不是一个默认字符串

10

func3只是为了找出其他类型是否可以使用相同的方法。
因此,问题是:在函数内创建指向字符串常量的指针(如func1()中)是否安全返回?
另外,使用默认字符串值(如func2()中)是否安全?


5
如果被放在引号中,它将永久存在。 - Neil Kirk
int j = 2; -- 那个2会存活多久?如果你可以这样做 int const *j = &2;,答案仍然是一样的。 - David Schwartz
2个回答

16
一个字符串字面量具有静态存储期,持续整个程序生命周期。根据C++草案标准2.14.5节中的“字符串字面量(String literals)”第8段所述(接下来是我的强调):“普通字符串字面量和UTF-8字符串字面量也称为窄字符串字面量。窄字符串字面量具有类型'数组n const char',其中n是如下定义的字符串的大小,并且具有静态存储期(3.7)。”另外,根据3.7.1节“静态存储期(Static storage duration)”第1段所述:“所有没有动态存储期、没有线程存储期且不是局部变量的变量具有静态存储期。这些实体的存储将持续整个程序(3.6.2,3.6.3)。”
另一方面,在func3的第二种情况是无效的。与引用绑定的临时对象的生存期将持续到引用的生命周期结束,而在本例中,当函数返回时就会结束。这在第12.2节中进行了讨论: “第二种情况是当引用绑定到临时对象时。与引用绑定的临时对象或作为其子对象的完整对象,在引用的生命周期内将持久存在,除非:”

或者永远存储在ROM中。我的意思是,指针可以指向任何地方,甚至是ROM中。 - user1095108
非常感谢!那么对于这里的func3呢?在函数返回到主函数后,它的返回值是否被期望为有效的? - SiLiKhon
1
@SiLiKhon,一般来说,这是行不通的。如果你将int更改为一个具有析构函数的类,当它超出范围时会发出类似于“destructing”的警告,你会发现在调用cout之前该对象已被销毁。在你的例子中,整数所在的内存尚未被覆盖,所以你很幸运能够打印出期望的值。 - triple_r

0
取决于它是什么类型的。
如果它是本地自动变量(指针),它将在堆栈上创建,并在函数执行期间存在。 当函数返回时,该指针将停止存在。 但是字符串字面量本身将在进程内存中存在,只要进程本身存在。
我只是试图演示在func1中发生的本地(自动)字符串初始化变量的情况。
我们看到使用相对寻址(当前地址+硬编码偏移量)来计算字符串字面量的地址。
这个地址被放置在寄存器 $rax 中。
由于 c 是局部变量,它应该在栈上定义,我们看到它使用 $rbp 中的栈地址放置在栈上。
当 func1 返回时,局部变量 c 将随着 func1 的栈帧一起销毁。
局部变量 c 将使用寄存器 $rax 返回。
我们在GDB的这个截图中看到了所有这些。

enter image description here

在返回主函数之前,我们看到本地字符串指针c的值被放置在寄存器$rax中,因此该寄存器用于将返回值传递给调用函数。
但是字符串字面量在哪里呢? 它位于ELF文件的.rodata节中,正如其名称所示,它是一个没有写权限的数据节。
Hex dump of section '.rodata':
0x00002000 01000200 4920616d 20612073 7472696e ....I am a strin
0x00002010 6720746f 6f004927 6d206120 73747269 g too.I'm a stri
0x00002020 6e670049 276d2061 20646566 61756c74 ng.I'm a default
0x00002030 20737472 696e6700 49276d20 6e6f7420  string.I'm not 
0x00002040 61206465 6661756c 74207374 72696e67 a default string

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接