引用内置类型的文本

Referring to literals of built-in type

提问人:sbi 提问时间:9/3/2018 最后编辑:sbi 更新时间:9/3/2018 访问量:146

问:

因此,我们在 Linux 上遇到了一个失败的测试,我想这源于我这边对引用内置文字的指针有效性的错误假设。该代码类似于以下伪代码:

auto obj = func( 'c', "str" ); // (1)
big_type big_object;           // (2) 

在 (1) 处,返回一个对象,该对象存储指向字符文本的常量指针和一个指向字符串文本的常指针。调试器中的检查显示两者都正确。func()

在 (2) 处,调试显示 const char* in 中引用的内存中曾经的 a 被覆盖了。'c'obj

Tets 表明这也发生在 和 字面上。这发生在 GCC 5.4.1 上,不会发生在 GCC 4.1.2 上。intdouble

C++做了 >25 年,我学会了假设,通常,编译器是对的,我是错的;所以我也在这里做这件事。

但是,虽然我知道,如果这只涉及小型内置类型的文字,我可以解决这个问题(通过复制它们而不是引用它们),如果这也可能发生在任意大小的对象()上,我们有一个相当大的问题。"str"

那么有人可以解释一下这方面的确切规则吗?

C++ 语言-律师 生存期

评论

0赞 Some programmer dude 9/3/2018
你说你存储了一个指向角色的指针?但是在不存在文字的函数中,你所拥有的只是参数变量,存储指向该变量的指针与存储指向局部变量的指针相同(参数基本上是局部变量)。如果没有合适的 MCVE,将很难告诉您其他任何事情。'c'
0赞 Useless 9/3/2018
如果你想确认这一点,只需将你的 func 更改为你想要存储的,并尝试作为参数传递。现在编译器怎么说?const char *&'c'
0赞 sbi 9/3/2018
@Some 假设函数为 。foo func(const char&, const char*)
0赞 sbi 9/3/2018
@Useless 我不认为我能耙出字符文字的地址,因为这是一个 rvalue。(请注意,我可以采用字符串文字的地址。

答:

1赞 John Zwinck 9/3/2018 #1

字符串文本在程序的整个生命周期中保持不变。字符文字则不然,因为它们实际上只是整数,并且没有对字符串进行任何特殊处理。

换个角度看:函数接收两个参数:一个是字符值,另一个是指向字符串文字的指针。复制指向字符串的指针是可以的,但创建指向作为参数传递的值的指针是不行的。就像你创建了一个指向指向字符串指针的指针一样。函数调用完成后,函数参数将被销毁。在字符大小写中,这意味着字符消失了,而在指向字符串的指针情况下,您已经制作了副本并保留了它。

4赞 Quentin 9/3/2018 #2

从 [expr.prim.literal§1]:

文字是主要表达式。它的类型取决于它的形式。字符串文字是左值;所有其他文本都是 pr值。

有关这些左值的更多精度,请参见 [lex.string§16]:

计算字符串文本会生成一个具有静态存储持续时间字符串文本对象,该对象从上面指定的给定字符初始化。[...]

这直接解决了这个问题:字符串文字是唯一具有静态存储持续时间的文字,因此可以由比它们出现的表达式更长的指针来引用。

评论

0赞 sbi 9/3/2018
是的,这是我们在午餐时讨论这个问题时也发现的关键点。更重要的是,问题不仅在于文字或内置函数,任何右值都会发生这种情况,例如 .幸运的是,这只是当前测试代码中的一个问题,因为在生产环境中,调用结果总是在完整表达式结束之前进行评估。因此,解决方案似乎是改变测试并添加一个严厉的警告,即其结果是不稳定的。既然你的答案是参考标准中相关经文的第一个答案,我就接受。std::string("temp")func()func()
2赞 Some programmer dude 9/3/2018 #3

假设定义如下:func

some_class_type func(const char& ch, const char* str)
{
    some_class_type some_object;
    some_object.pch = &ch;
    some_object.pstr = str;
    return some_object;
}

然后,使用 存储指向临时变量的指针。&ch

的生存期不是完整的程序,直到完整表达式(即调用)结束,那么临时变量将不复存在,你只剩下一个杂散的指针。chfunc('c', "str")

对于单个字符,例如单个整数或浮点值,几乎不需要使用指向它们的指针。存储值。

1赞 Useless 9/3/2018 #4

对于确切的规则,指出以下关于字符串文字的句子可能就足够了(尽管昆汀的标准引用显然更权威)

字符串文本具有静态存储持续时间,因此在程序的生命周期内存中存在

对于任何其他类型的文字都不存在。

另一种看待它的方法是重新检查你的代码

object func(char c, const char *s)
{
    return object{&c, s};
}

请注意,字符串文本不是按值传递的。因为(一旦它衰减到指针)你只是传递第一个字符的地址 - 该数组必须至少保持一段时间有效,并且由于没有办法知道生存期应该是多少,静态持续时间是一个合理的默认值。