C++ 中的静态类数据与匿名命名空间
我偶尔会有带有私有静态数据成员的类。 我目前正在争论是否应该将它们替换为实现文件中未命名命名空间中的静态变量。 除了不能在内联方法中使用这些变量之外,还有其他缺点吗? 我看到的优点是,它们对类的用户完全隐藏。
I occasionally have classes with private static data members. I'm currently debating if I should replace these with static variables in an unnamed namespace in the implementation file. Other that not being able to use these variables in inline methods, are there any other drawbacks? The advantage that I see is that is hides them completely from the users of the class.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我不相信这种好处值得可读性影响。 我通常认为私人的东西“足够隐藏”。
I'm not convinced that the benefit is worth the readability impact. I generally consider something that's private to be "hidden enough."
1)存在一个缺点,即对二进制组织的附加限制。 在 20 世纪 90 年代 C++ 会议上的一次演讲中,Walter Bright 报告称,通过组织代码以使相互调用的函数位于同一编译单元中,实现了显着的性能提升。 例如,如果在执行期间 Class1::method1 对 Class2 方法的调用远多于对其他 Class1::methods 的调用,则在 class2.cpp 中定义 Class1::method1 意味着 Class1::method1 将与这些方法位于同一代码页上它正在调用,因此不太可能因页面错误而延迟。 这种重构对于类静态比文件静态更容易进行。
2) 反对引入命名空间关键字的论点之一是“你可以用类做同样的事情”,你会看到类和结构在来自以下来源的源代码中被用作穷人的命名空间:前命名空间时代。 令人信服的反驳是因为名称空间是可重新打开的,任何地方的任何函数都可以使其成为名称空间的一部分或访问外部名称空间,那么您可以使用名称空间做一些您不能做的事情 上课。 这与您的问题有关,因为它表明语言委员会正在将名称空间范围视为与类范围非常相似; 这减少了使用匿名命名空间而不是类静态时出现一些微妙的语言陷阱的可能性。
1) There is a drawback in the form of an added restriction on binary organization. In a presentation at a C++ conference in the 1990s, Walter Bright reported achieving significant performance increases by organizing his code so that functions that called each other were in the same compilation unit. For example, if during execution Class1::method1 made far more calls to Class2 methods than to other Class1::methods, defining Class1::method1 in class2.cpp meant that Class1::method1 would be on the same code page as the methods it was calling, and thus less likely to be delayed by a page fault. This kind of refactoring is easier to undertake with class statics than with file statics.
2) One of the arguments against introducing the namespace keyword was "You can do the same thing with a class," and you will see class and struct being used as a poor-man's namespace in sources from the pre-namespace era. The convincing counter-argument was because namespaces are re-openable, and any function anywhere can make itself part of a namespace or access a foreign namespace, then there were things you could do with a namespace that you could not do with a class. This has bearing on your question because it suggests that the language committee was thinking of namespace scope as very much like class scope; this reduces the chance that there is some subtle linguistic trap in using an anonymous namespace instead of a class static.
我不同意其他答案。 尽量远离课堂
尽可能的定义。
在 Scott Meyers 的《Effective C++ 第三版》 中,他建议优先选择非友元
函数到类方法。 这样,类定义如下
尽可能小,私有数据在尽可能少的地方被访问
可能(封装)。
遵循这一原则进一步导致了 pimpl 惯用法。 然而,
需要平衡。 确保您的代码是可维护的。 盲目地,
遵循此规则将导致您创建所有私有方法
文件本地并只需传入所需的成员作为参数。 这
会改进封装,但会破坏可维护性。
话虽如此,文件本地对象很难进行单元测试。 和
一些聪明的黑客可以在单元测试期间访问私有成员。
访问文件本地对象的涉及更多。
I disagree with the other answers. Keep as much out of the class
definition as possible.
In Scott Meyers' Effective C++ 3rd edition he recommends preferring non-friend
functions to class methods. In this way the class definition is as
small as possible, the private data is accessed in as few places as
possible (encapsulated).
Following this principle further leads to the pimpl idiom. However,
balance is needed. Make sure your code is maintainable. Blindly,
following this rule would lead you to make all your private methods
file local and just pass in the needed members as parameters. This
would improve encapsulation, but destroy maintainability.
All that said, file local objects are very hard to unit test. With
some clever hacking you can access private members during unit tests.
Accessing file local objects is a bit more involved.
它不仅对班级用户隐藏它们,而且对您隐藏它们! 如果这些变量是类的一部分,它们应该以某种方式与类相关联。
根据您要对它们执行的操作,您可以考虑将它们设置为静态成员函数中的静态变量:
It not only hides them from users of the class, it hides them from you! If these variables are part of the class, they should be associated with the class in some way.
Depending on what you are going to do with them, you could consider making them static variables inside static member functions:
我想这可以归结为这些变量在类的上下文中是否具有一些实际含义(例如,指向所有对象使用的一些公共内存的指针),或者只是需要在方法之间传递的一些临时数据,并且不想混乱类与. 在后一种情况下,我肯定会使用未命名的名称空间。 对于前者,我想说这是个人品味问题。
I guess it boils down to whether these variables have some actual meaning in the context of the class (e.g., pointer to some common memory used by all objects) or just some temporary data you need to pass around between methods and would rather not clutter the class with. In the latter case I would definitely go with the unnamed namespace. In the former, I'd say it's a matter of personal taste.
我部分同意 Greg 的观点,因为未命名的命名空间成员并不比私有数据更封装。 毕竟,封装的目的是向其他模块隐藏实现细节,而不是向其他程序员隐藏。 尽管如此,我确实认为在某些情况下这是一种有用的技术。
考虑如下的类:
在这种情况下,任何想要使用 Foo 的模块也必须知道 Bar 的定义,即使该定义无关紧要。 这些类型的标头依赖性导致更频繁和更长的重建。 将 helper 的定义移动到 Foo.cpp 中的未命名命名空间是打破这种依赖关系的好方法。
我也强烈不同意这样的观点:未命名的命名空间在某种程度上比静态数据成员可读性或可维护性较差。 从标题中删除不相关的信息只会使其更加简洁。
I agree partly with Greg, in that unnamed namespace members aren't any more encapsulated than private data. The point of encapsulation, after all, is to hide implementation details from other modules, not from other programmers. Nevertheless, I do think there are some cases where this is a useful technique.
Consider a class like the following:
In this case, any module that wants to use Foo must also know the definition of Bar even though that definition is of no relevance what-so-ever. These sort of header dependencies lead to more frequent and lengthier rebuilds. Moving the definition of helper to an unnamed namespace in Foo.cpp is a great way to break that dependency.
I also disagree strongly with the notion that unnamed namespaces are somehow less readable or less maintainable than static data members. Stripping irrelevant information from your header only makes it more concise.