函数返回后,指向字符串字面量的指针是否仍然有效?

20

以下函数返回的指针是否有效?

const char * bool2str( bool flg )
{
    return flg ? "Yes" : "No";
}

它在Visual C++和g++中运行良好。C++标准对此有何规定?


2
是的。但在C++中,您仍应优先选择std::string。请参见下文。 - Martin York
4个回答

26

关于存储持续时间:

2.13.4 普通字符串字面值和UTF-8字符串字面值也被称为窄字符串字面值。窄字符串字面值的类型为“长度为n的const char数组”,其中n定义为下面所述的字符串的大小,并且具有静态存储持续时间。

结合3.7.1阅读

3.7.1.

所有没有动态存储持续时间、没有线程存储持续时间并且不是本地的对象都具有静态存储持续时间。这些对象的存储将持续整个程序(3.6.2,3.6.3)。

关于类型:

附录C

子句2.13.4:

更改:将字符串字面值设置为const。字符串字面值的类型从“char数组”更改为“const char数组”。char16_t字符串字面值的类型从“某种整数类型的数组”更改为“const char16_t数组”。char32_t字符串字面值的类型从“某种整数类型的数组”更改为“const char32_t数组”。宽字符串字面值的类型从“wchar_t数组”更改为“const wchar_t数组”。

原理:这避免了调用不适当的重载函数,该函数可能期望能够修改其参数。

对原始特性的影响:改变了明确定义功能的语义。转换难度:简单的语法转换,因为字符串字面值可以转换为char*(4.2)。最常见的情况由新的但已弃用的标准转换处理:char* p =“abc”; //在C中有效,在C ++中已弃用 char* q = expr?“abc”:“de”; //在C中有效,在C ++中无效

使用范围:将字符串字面值视为指向可能修改的内存的指针的程序可能很少见。

动态分配的(在标准中似乎从未使用“堆”一词来描述内存区域)内存需要一个函数调用,该调用可能在静态内存分配之后很早就发生,甚至可以在main函数中进行。


+1 分钟,但是你引用的标准不太准确(至少是2.13.4)。 - Kirill V. Lyadvinsky
关于C-Strings的标准用法的引用可能也会很有用。在C世界中,更标准的做法是返回一个动态分配的char*指针,因此需要释放它。如果不遵循这个惯例,那么你的代码将无法与现有库很好地配合。 - Martin York
1
@Kirill V. Lyadvinsky:这段内容摘自C++0x草案N-4411(由我在评论中提到)。 - dirkgently
4
这个回答缺乏明确的“是”或“否”,只是将读者埋在标准文件的引用中。 - rubenvb

13
这段代码是完全有效和符合标准的。唯一的注意点是确保调用者不尝试释放该字符串。

1
不需要。这些字面量是“const char []”,它们从未在堆上分配。返回的指针将在整个程序执行期间有效。 - David Rodríguez - dribeas
1
没有“'const char []'”。 - Alexey Malistov
尝试通过freedelete释放内存应该会引起诊断(参数类型不匹配)。因此,在这方面你也是安全的。 - dirkgently
永远不要堆分配。为什么?有任何参考资料吗? - Alexey Malistov
@Alexey Malistov:字符串字面值的有效类型是大小为N的常量字符数组。 - dirkgently
5
标准将其称为“静态存储”。请参阅草案N-4411的2.13.4。请参阅附录C,了解类型为何为静态。 - dirkgently

12

这段代码是有效的且符合标准。

字符串字面值存储在只读内存中,该函数只是获取所选字符串的地址。

C++标准(2.13.4)指出:

普通字符串字面值的类型为“n个const char的数组”,并具有静态存储期

理解这里的问题关键在于静态存储期:字符串字面值在程序启动时分配,并持续到程序结束。您的函数只是获取并返回其地址。


5

从技术上讲,是的,它是有效的。这些字符串具有静态存储持续时间。

但这还不是全部。

这些是C字符串。在C库和函数中的惯例是返回应该被释放的动态分配的字符串的指针。也就是说,返回的指针隐含地将所有权传递回调用者(通常在C中也有例外情况)。

如果您不遵循这些惯例,那么会混淆许多经验丰富的C开发人员,他们会期望这种约定。如果您不遵循这个标准的期望,那么它应该在代码中得到充分的记录。

此外,这是C++(根据您的标签)。因此,更常规的做法是返回std::string。原因是通过指针传递所有权仅仅是暗示的(这导致了许多错误,在C代码中违反了上述期望但已记录,不幸的是,代码的用户从未阅读过文档)。通过使用std::string,您正在传递一个对象,因此不再存在所有权问题(结果作为值传回,因此是您的),但由于它是一个对象,所以不存在任何资源分配的问题或疑问。

如果您担心效率,我认为这是一个虚假的担忧。

如果您想通过流打印此内容,那么已经有一个标准约定可以实现:

std::cout << std::boolalpha << false << std::endl;
std::cout << std::boolalpha << true  << std::endl;

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