const 正确性如何帮助编写更好的程序?
这个问题是一个 C# 人问 C++ 人的问题。 (我懂一点 C,但只有一些 C++ 的一般知识)。
很多接触 C# 的 C++ 开发人员表示他们怀念 const 的正确性,这对我来说似乎很奇怪。 在.Net中,为了禁止更改,您需要创建不可变对象或具有只读属性/字段的对象,或者传递对象的副本(默认情况下复制结构)。
C++ const 正确性是一种创建不可变/只读对象的机制,还是还有更多内容? 如果目的是创建不可变/只读对象,则可以在 .Net 等环境中完成相同的操作。
This question is from a C# guy asking the C++ people. (I know a fair bit of C but only have some general knowledge of C++).
Allot of C++ developers that come to C# say they miss const correctness, which seems rather strange to me. In .Net in order to disallow changing of things you need to create immutable objects or objects with read only properties/fields, or to pass copies of objects (by default structs are copied).
Is C++ const correctness, a mechanism to create immutable/readonly objects, or is there more to it? If the purpose is to create immutable/readonly objects, the same thing can be done in an environment like .Net.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
常见问题解答中有一整节专门介绍常量正确性。 享受!
A whole section is devoted to Const Correctness in the FAQ. Enjoy!
C++ 中的 const 正确性本质上只是一种准确表达您的意思的方式:
表示“我不会更改 t 引用的对象,如果我尝试这样做,请编译器先生警告我”。
它不是一种安全功能,也不是一种(可靠地)创建只读对象的方法,因为使用 C 风格的强制转换很容易破坏。
const correctness in C++ is at heart simply a way of saying exactly what you mean:
says "I will not change the object referred to by t, and if I try to, please Mr. Compiler warn me about it".
It is not a security feature or a way of (reliably) creating read-only objects, because it is trivial to subvert using C-style casts.
我敢打赌这是一个心态问题。 我自己与长期使用 C++ 的人一起工作,并注意到他们似乎用 C++ 思考(当然是这样!)。 他们需要一段时间才能开始看到他们已经熟悉的答案的多个答案,从而获得像 const 正确性这样的“库存”答案。 给他们时间,并尝试温和地教育他们。
话虽如此,我确实喜欢 C++ 的“const”保证方式。 它主要是向接口的用户承诺,指针后面的对象、数据或任何内容都不会被弄乱。 我将其视为 const 正确性的第一值。 #2 值是它可以允许编译器进行优化的值。
当然,问题在于,如果整个软件堆栈在构建时没有从头开始就考虑到 const。
我确信 C# 有它自己的一套范例来完成同样的事情。 这说明了为什么“每年学习一门新的(计算或自然)语言”如此重要。 只是为了锻炼一个人以其他方式看待世界并解决问题的头脑。
I bet this is a matter of mindsets. I'm working myself with long-time C++ people and have noticed they seem to think in C++ (of course they do!). It will take time for them to start seeing multiple answers to the ones they've grown familiar to have the 'stock' answers like const correctness. Give them time, and try to educate them gently.
Having said that, I do like the C++ 'const' way of guarantees. It's mainly promising the user of an interface that the object, data behind the pointer or whatever won't be messed with. I would see this as the #1 value of const correctness. #2 value is what it can allow the compiler in terms of optimization.
The problem is, of course, if the whole sw stack hasn't been built with const in mind from the ground up.
I'm sure C# has its own set of paradigms to do the same. This shows why it's so important to "learn one new (computing or natural) language a year". Simply to exercise one's mind of the other ways to see the world, and solve its problems.
通过常量正确性,您可以将可变对象公开为只读而无需复制它并浪费宝贵的内存(尤其与集合相关)。 我知道,桌面开发人员中存在这种CPU 和内存都很便宜的理念,但它在嵌入式世界中仍然很重要。
最重要的是,如果在 C++ 中增加内存所有权的复杂性,那么最好不要复制包含或引用其他对象的重要对象,因此有一种将现有对象公开为只读的方法。
With const-correctness, you can expose a mutable object as read-only without making a copy of it and wasting precious memory (especially relevant for collections). I know, there is this CPU-and-memory-are-cheap philosophy among desktop developers, but it still matters in embedded world.
On top of that, if you add complexities of memory ownership in C++, it is almost always better not to copy non-trivial objects that contain or reference other objects, hence there is a method of exposing existing objects as read-only.
优秀的 Scott Meyer 的书 Effective C++ 专门针对此问题提供了一个项目:
ITEM 3 : 尽可能使用const。
它真的启发了你:-)
Excellent Scott Meyer's book Effective C++ has dedicated an item to this issue:
ITEM 3: Use const whenever possible.
It really enlightens you :-)
真正的答案是,你失去了表现力,即使如果你没有使用它的话真的很难理解。 该语言具有无法在 C# 中表达的概念,它们具有意义,它们是设计的一部分,但在转换为代码时丢失了。
这不是一个答案,而是一个示例:
假设您有一个容器,它根据存储的元素的字段进行排序。 这些物体确实很大。 您需要为读者提供对数据的访问(考虑在 UI 中显示信息)。
现在,在 C#/Java 中,您可以采用以下两种方式之一:要么制作一个副本供调用者使用(保证数据不会更改,但效率低下),要么返回对内部保存的对象的引用(只需希望调用者不会通过设置器更改您的数据)。
如果用户获取引用并通过它更改用作索引的字段,那么您的容器不变量就会被破坏。
在 C++ 中,您可以返回常量引用/指针,编译器将禁止在您返回的实例上调用 setter 方法(变异方法)。 您可以获得用户不会更改的安全性 (*) 和呼叫的效率。
前面没有提到的第三个选项是使对象不可变,但这会禁用任何地方的更改。 不允许对对象进行完全受控的更改,并且更改的唯一可能性是通过执行的更改创建一个新元素。 这相当于时间和空间。
The real answer, even if it is really hard to grasp if you have not used it, is that you loose expressiveness. The language has concepts that you cannot possibly express in C#, and they have meaning, they are part of the design, but lost in the translation to code.
This is not an answer, but rather an example:
Consider that you have a container that is sorted on a field of the elements that are stored. Those objects are really big. You need to offer access to the data for readers (consider showing the information in the UI).
Now, in C#/Java, you can go in one of two ways: either you make a copy for the caller to use (guarantees that the data will not change, but inefficient) or you return a reference to your internally held object (just hoping the caller will not change your data through setters).
If the user gets the reference and changes through it the field that serves as index, then your container invariants are broken.
In C++ you can return a constant reference/pointer, and the compiler will disable calling setter methods (mutating methods) on the instance you return. You get both the security that the user will not change (*) and efficiency in the call.
The third not mentioned before option is making the object inmutable, but that disables changes everywhere. Perfectly controlled changes to the object will be disallowed, and the only possibility of change is creating a new element with the changes performed. That amounts to time and space.
C++ 提供了很多可能弄乱代码的方法。 我认为 const 正确性是对代码施加约束的第一个有效方法,以控制“副作用”(不需要的更改)。
将参数标记为 const(通常引用 const 对象或指向 const 对象的指针)将确保传递的对象无法更改,因此该函数/方法不会产生“副作用”。
将方法标记为 const 将保证该方法不会更改它所使用的对象的状态。 如果是这样,编译器将生成错误。
标记const数据成员将确保该数据成员只能在构造函数的初始化列表中初始化并且不能被更改。
此外,智能编译器可以使用常量作为各种性能优化的提示。
当然,您可以覆盖常量。 常量是编译时检查。 默认情况下,您不能违反规则,但您可以使用强制转换(例如 const_cast)将 const 对象设为非 const,以便可以更改它。
C++ provides plenty of ways you can mess up your code. I see const correctness as a first, efficient way of putting constraints to the code, in order to control the "side" effects (unwanted changes).
Marking a parameter as const (usually reference to const object or pointer to const object), will ensure that the passed object can't be changed, so you have no "side" effect of that function/method.
Marking a method as const will guarantee that that method will not change the state of the object it works with. If it does, the compiler will generate an error.
Marking a const data member will ensure that the data member can only be initialized in the initialization list of the constructor and can't be changed.
Also, smart compilers can use the constness as hints for various performance optimizations.
Of course, you can override constness. Constness is compile time checking. You can't break the rules by default, but you can use casting (e.g. const_cast) to make a const object non-const so it can be changed.
在编写代码时仅寻求编译器的帮助就足以让我提倡常量正确性。 但现在还有一个额外的优势:当您知道我们的对象在哪里可以更改以及在哪里不能更改时,多线程代码通常更容易编写。
Just enlisting the compiler's help when writing code would be enough for me to advocate const-correctness. But today there is an additional advantage: multi-threading code is generally easier to write when you know where can our objects change and where they cannot.
我认为遗憾的是 C# 不像 C++ 那样支持 const 正确性。 我传递给函数的所有参数中 95% 都是常量值,const 功能保证您通过引用传递的数据在调用后不会被修改。 “const”关键字提供编译器检查的文档,这对大型程序有很大帮助。
I think it's a pity C# doesn't support const correctness as C++ does. 95% of all parameters I pass to a function are constant values, the const feature guarantees that the data you pass by reference won't be modified after the call. The "const" keyword provides compiler-checked documentation, which is a great help in large programs.