GNU _M_ 前缀的背后思想是什么?

6
如果我们看一下GNU实现的libstdc++,我注意到在各种类的标准实现中,私有成员函数都以_M_为前缀。例如,std::basic_string<>有一个叫做bool _M_is_shared() const;的成员,还有其他的成员。
我理解使用某种命名约定来区分私有成员变量和函数局部变量的动机。但我不明白为什么私有成员函数更喜欢使用_M_前缀。
如果我看到某些代码调用了例如:is_shared();,那么基本上只有几个选项:
1. 它是这个类的成员函数 2. 它是父类的成员函数 3. 它是全局函数。
前两个都有前缀,所以没有帮助。最后一个由于命名空间污染问题,在任何理智的实现中不会发生。库应该引入的唯一全局变量是标准规定的变量。所以这里的关键问题是...
由于私有成员函数不能公开访问,也不能影响派生类。我认为名称冲突在这里并不是真正的问题...基本上这些只是私有实现细节。为什么要费心(在我看来)丑陋的_M_前缀?标准中是否有禁止引入额外私有成员的规定?如果是这样,除非我漏掉了什么,否则这会让我感到愚蠢。

可能是为什么STL的命名约定使用了这么多前导下划线?的重复问题。在GNU C++库中,我们使用__foo表示局部变量和参数,使用_M_foo_S_foo表示成员变量,但在两种情况下,我们都必须使用保留名称来确保不与用户定义的任何宏发生冲突。 - Jonathan Wakely
2个回答

5

以下划线和大写字母开头或以两个下划线开头的标识符在所有情况下都被保留给实现。

这意味着根据标准,某人的程序如果使用#define _M_is_shared false这样的标识符并破坏库头文件将是非法的。 如果他们使用更常见的标识符,则更容易在其他有效程序中发生名称冲突。


啊!我没有想到有人会使用宏来重新定义头文件中的私有内容...太邪恶了 :-P - Evan Teran
我不知道它是否邪恶...尽管被“保留”,你仍然可以编译代码,这些代码完全违反了保留的命名约定(如果人们要更改实现,你基本上必须允许这种情况)。保留名称是一个指南,可以更安全地使用,但不能阻止任何人做任何事情。 - IdeaHat
2
@MadScienceDreams: 17.6.4.3/2:“如果程序在保留的上下文中声明或定义名称,除非明确允许此条款,否则其行为是未定义的。” 是的,你可以这样做,但标准规定这样做与取消引用nullptr一样糟糕,任何出错都是程序的问题,而不是实现的问题。 - aschepler
@aschepler 抱歉,我并不是在批评你,你说得完全正确。试图干预实现是一个非常糟糕的想法。我只是指出这是允许的,并且你唯一会这样做的原因是为了改变库的实现。 - IdeaHat
@MadScienceDreams,不行!虽然预处理器有时很愚蠢,不会阻止你这样做,但如果你的程序出了问题,你就得自己承担。而且,如果你在宏中使用保留名称,符合规范的实现可能会拒绝你的代码。 - Jonathan Wakely

3
标准指定以双下划线开头的名称,或者下划线后跟大写字母的名称,保留用于内部编译器或库符号。
你指出这些私有符号将不可访问,但别忘了宏和定义。基本上,这个想法很简单,就像“让我们用 '_M_member' 替换 'm_member'”。
标准相关的部分是 17.4.3.1.2 全局名称
每个包含双下划线 "__" 或以下划线开头并且后面紧跟一个大写字母的名称都保留给实现作为任何用途。

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