2

这个问题来自一个 C# 的人问 C++ 的人。(我对 C 有一定的了解,但只对 C++ 有一些常识)。

很多使用 C# 的 C++ 开发人员说他们错过了 const 的正确性,这对我来说似乎很奇怪。在 .Net 中,为了禁止更改事物,您需要创建不可变对象或具有只读属性/字段的对象,或传递对象的副本(默认情况下复制结构)。

是 C++ const 正确性,一种创建不可变/只读对象的机制,还是还有更多?如果目的是创建不可变/只读对象,则可以在 .Net 等环境中完成相同的操作。

4

9 回答 9

13

FAQ 中有一整节专门讨论Const 正确性。享受!

于 2009-04-13T09:47:27.153 回答
7

C++ 中的 const 正确性本质上只是一种准确表达您的意思的方式:

void foo( const sometype & t ) {
   ...
}

说“我不会更改 t 引用的对象,如果我尝试更改,请编译器先生警告我”。

它不是一种安全特性,也不是一种(可靠地)创建只读对象的方式,因为使用 C 风格的转换来颠覆是微不足道的。

于 2009-04-13T09:42:11.143 回答
6

我敢打赌,这是一个心态问题。我正在与长期使用 C++ 的人一起工作,并注意到他们似乎在用 C++ 思考(他们当然会这样做!)。他们需要时间才能开始看到他们已经熟悉的答案的多个答案,以获得像 const 正确性这样的“标准”答案。给他们时间,试着温和地教育他们。

话虽如此,我确实喜欢 C++ 'const' 的保证方式。它主要是向接口的用户保证对象、指针后面的数据或其他任何东西都不会被弄乱。我会将此视为 const 正确性的 #1 值。#2 值是它可以允许编译器在优化方面的值。

当然,问题是,如果整个 sw 堆栈没有从头开始构建时考虑到 const。

我确信 C# 有自己的一套范例来做同样的事情。这说明了为什么“每年学习一种新的(计算或自然)语言”如此重要。只是为了锻炼一个人的其他方式来看待世界,解决它的问题。

于 2009-04-13T09:49:56.147 回答
4

使用 const-correctness,您可以将可变对象公开为只读,而无需复制它并浪费宝贵的内存(尤其是与集合相关)。我知道,桌面开发人员有这种CPU 和内存便宜的理念,但它在嵌入式世界中仍然很重要。

最重要的是,如果在 C++ 中添加内存所有权的复杂性,最好不要复制包含或引用其他对象的非平凡对象,因此有一种方法可以将现有对象公开为只读。

于 2009-04-13T09:42:21.470 回答
3

优秀的 Scott Meyer 的《 Effective C++ 》一书专门针对这个问题发表了一篇文章:

第 3 项:尽可能使用 const。

它真的启发了你:-)

于 2009-04-13T10:16:49.407 回答
3

真正的答案,即使你没有使用它真的很难掌握,是你失去了表现力。该语言具有您无法在 C# 中表达的概念,它们具有意义,它们是设计的一部分,但在转换为代码时丢失了。

这不是一个答案,而是一个例子:

假设您有一个容器,该容器按存储的元素的字段进行排序。那些物体真的很大。您需要为读者提供对数据的访问权限(考虑在 UI 中显示信息)。

现在,在 C#/Java 中,您可以采用以下两种方式之一:要么制作副本供调用者使用(保证数据不会更改,但效率低下),要么返回对内部持有对象的引用(只需希望调用者不会通过设置器更改您的数据)。

如果用户获取引用并通过它更改用作索引的字段,那么您的容器不变量将被破坏。

在 C++ 中,您可以返回一个常量引用/指针,编译器将禁用在您返回的实例上调用 setter 方法(变异方法)。您可以获得用户不会更改的安全性 (*) 和通话效率。

之前没有提到的第三个选项是使对象不可变,但这会在任何地方禁用更改。将不允许对对象进行完全受控的更改,唯一可能的更改是创建一个执行更改的新元素。这相当于时间和空间。

于 2009-04-13T11:16:53.037 回答
2

C++ 提供了很多方法可以让你搞乱你的代码。我认为 const 正确性是对代码施加约束的第一种有效方式,以控制“副作用”(不需要的更改)。

将参数标记为 const(通常引用 const 对象或指向 const 对象的指针)将确保传递的对象无法更改,因此您没有该函数/方法的“副作用”。

将方法标记为 const 将保证该方法不会改变它所使用的对象的状态。如果是这样,编译器将生成错误。

标记一个 const 数据成员将确保该数据成员只能在构造函数的初始化列表中进行初始化,而不能更改。

此外,智能编译器可以使用常量作为各种性能优化的提示。

当然,您可以覆盖 constness。常量是编译时检查。默认情况下您不能违反规则,但您可以使用强制转换(例如 const_cast)使 const 对象成为非 const 对象,以便对其进行更改。

于 2009-04-13T10:13:56.107 回答
1

仅仅在编写代码时寻求编译器的帮助就足以让我提倡 const 正确性。但是今天还有一个额外的优势:当您知道我们的对象在哪里可以更改以及在哪里不能更改时,多线程代码通常更容易编写。

于 2009-04-13T09:50:47.910 回答
1

我认为遗憾的是 C# 不像 C++ 那样支持 const 正确性。我传递给函数的所有参数中有 95% 是常量值,const 特性保证您通过引用传递的数据在调用后不会被修改。“const”关键字提供了经过编译器检查的文档,这对大型程序有很大帮助。

于 2009-04-15T09:37:45.490 回答