为什么常量正确性特定于 C++?

发布于 2024-08-03 21:01:58 字数 1622 浏览 6 评论 0原文

免责声明:我知道有两个关于 const 正确性的有用性的问题,但是,没有人讨论 const 正确性在 C++ 中与其他编程语言不同的必要性。此外,我也不满意以及这些问题的答案。

我现在已经使用了几种编程语言,在 C++ 中让我烦恼的一件事是常量正确性的概念。 Java、C#、Python、Ruby、Visual Basic 等中没有这样的概念,这似乎是 C++ 特有的。

在您向我推荐 C++ FAQ Lite 之前,我已经阅读过它,但它并不能说服我。完全有效、可靠的程序始终是用 Python 编写的,并且不存在 const 关键字或等效关键字。在Java和C#中,对象可以声明为final(或const),但没有const成员函数或const函数参数。如果函数不需要修改对象,它可以采用仅提供对该对象的读取访问的接口。该技术同样可以在 C++ 中使用。在我工作过的两个现实世界的 C++ 系统上,几乎没有使用 const,而且一切都运行良好。所以我根本不相信让 const 污染代码库的用处。

我想知道在 C++ 中是什么使得 const 成为必需的,与其他编程语言不同。

到目前为止,我只见过一种必须使用 const 的情况:

#include <iostream>

struct Vector2 {
    int X;
    int Y;
};

void display(/* const */ Vector2& vect) {
    std::cout << vect.X << " " << vect.Y << std::endl;
}

int main() {
    display(Vector2());
}

Visual Studio 接受使用 const 注释掉的方式进行编译,但带有警告 C4239,使用非标准扩展。因此,如果您希望传递临时变量、避免复制并保持符合标准的语法简洁,则必须通过 const 引用传递,没有办法绕过它。不过,这更像是一个怪癖,而不是根本原因。

否则,实际上没有必要使用 const 的情况,除非与使用 const 的其他代码进行交互。在我看来,Const 只不过是一场自以为是的瘟疫,蔓延到它所接触到的一切:

const 在 C++ 中起作用的原因是 因为你可以把它扔掉。如果你 无法抛弃,那么你的世界 会很糟糕。如果你声明一个方法 这需要一个 const Bla,你可以通过 它是非常量的 Bla。但如果是 否则你就不能。如果你 声明一个方法,该方法采用 非常量 Bla,你不能通过它 常量 Bla。所以现在你被困住了。所以你 逐渐需要一个cons版本 一切非 const 的东西,还有你 最终进入一个影子世界。在 C++ 中你 摆脱它,因为就像 C++ 中的任何内容都是纯粹可选的 无论您是否想要这张支票。 你可以把常量打掉 如果你不喜欢它。

Anders Hejlsberg(C# 架构师),CLR 设计选择

Disclaimer: I am aware that there are two questions about the usefulness of const-correctness, however, none discussed how const-correctness is necessary in C++ as opposed to other programming languages. Also, I am not satisfied with the answers provided to these questions.

I've used a few programming languages now, and one thing that bugs me in C++ is the notion of const-correctness. There is no such notion in Java, C#, Python, Ruby, Visual Basic, etc., this seems to be very specific to C++.

Before you refer me to the C++ FAQ Lite, I've read it, and it doesn't convince me. Perfectly valid, reliable programs are written in Python all the time, and there is no const keyword or equivalent. In Java and C#, objects can be declared final (or const), but there are no const member functions or const function parameters. If a function doesn't need to modify an object, it can take an interface that only provides read access to the object. That technique can equally be used in C++. On the two real-world C++ systems I've worked on, there was very little use of const anywhere, and everything worked fine. So I'm far from sold on the usefulness of letting const contaminate a codebase.

I am wondering what is it in C++ that makes const necessary, as opposed to other programming languages.

So far, I've seen only one case where const must be used:

#include <iostream>

struct Vector2 {
    int X;
    int Y;
};

void display(/* const */ Vector2& vect) {
    std::cout << vect.X << " " << vect.Y << std::endl;
}

int main() {
    display(Vector2());
}

Compiling this with const commented out is accepted by Visual Studio, but with warning C4239, non-standard extension used. So, if you want the syntactic brevity of passing in temporaries, avoiding copies, and staying standard-compliant, you have to pass by const reference, no way around it. Still, this is more like a quirk than a fundamental reason.

Otherwise, there really is no situation where const has to be used, except when interfacing with other code that uses const. Const seems to me little else than a self-righteous plague that spreads to everything it touches :

The reason that const works in C++ is
because you can cast it away. If you
couldn't cast it away, then your world
would suck. If you declare a method
that takes a const Bla, you could pass
it a non-const Bla. But if it's the
other way around you can't. If you
declare a method that takes a
non-const Bla, you can't pass it a
const Bla. So now you're stuck. So you
gradually need a const version of
everything that isn't const, and you
end up with a shadow world. In C++ you
get away with it, because as with
anything in C++ it is purely optional
whether you want this check or not.
You can just whack the constness away
if you don't like it.

Anders Hejlsberg (C# architect), CLR Design Choices

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

孤寂小茶 2024-08-10 21:01:58

我能想到,Const 正确性为 C++ 提供了两个显着的优势,其中之一使其相当独特。

  • 它允许可变/不可变数据的普遍概念,而不需要一堆接口。可以对各个方法进行注释以确定它们是否可以在 const 对象上运行,并且编译器会强制执行此操作。是的,有时这可能会很麻烦,但如果您一致地使用它并且不使用 const_cast ,您就可以在可变数据与不可变数据方面进行编译器检查的安全性。
  • 如果对象或数据项是 const,编译器可以自由地将其放置在只读内存中。这在嵌入式系统中尤其重要。 C++ 支持这一点;很少有其他语言这样做。这也意味着,在一般情况下,您无法安全地转换 const ,尽管实际上您可以在大多数环境中这样做。

C++ 并不是唯一具有 const 正确性或类似特性的语言。 OCaml 和标准 ML 有类似的概念,但术语不同——几乎所有数据都是不可变的(const),当您希望某些内容可变时,您可以使用不同的类型(ref 类型)来实现这一点。因此,它是 C++ 在其邻近语言中所独有的。

最后,转向另一个方向:有时我想在 Java 中使用 const。 final 有时在创建简单的不可变数据(尤其是可变数据的不可变视图)方面还不够,并且不想创建接口。看看 Java API 中对不可修改集合的支持,以及它仅在运行时检查是否允许修改的事实,这就是为什么 const 有用的示例(或者至少应该加深接口结构以拥有 List 和 MutableList) - 那里尝试改变不可变结构没有理由不会出现编译类型错误。

Const correctness provides two notable advantages to C++ that I can think of, one of which makes it rather unique.

  • It allows pervasive notions of mutable/immutable data without requiring a bunch of interfaces. Individual methods can be annotated as to whether or not they can be run on const objects, and the compiler enforces this. Yes, it can be a hassle sometimes, but if you use it consistently and don't use const_cast you have compiler-checked safety with regards to mutable vs. immutable data.
  • If an object or data item is const, the compiler is free to place it in read-only memory. This can particularly matter in embedded systems. C++ supports this; few other languages do. This also means that, in the general case, you cannot safely cast const away, although in practice you can do so in most environments.

C++ isn't the only language with const correctness or something like it. OCaml and Standard ML have a similar concept with different terminology — almost all data is immutable (const), and when you want something to be mutable you use a different type (a ref type) to accomplish that. So it's just unique to C++ within its neighboring languages.

Finally, coming the other direction: there have been times I have wanted const in Java. final sometimes doesn't go far enough as far as creating plainly immutable data (especially immutable views of mutable data), and don't want to create interfaces. Look at the Unmodifiable collection support in the Java API and the fact that it only checks at run time whether modification is allowed for an example of why const is useful (or at least the interface structure should be deepend to have List and MutableList) — there is no reason that attempting to mutate an immutable structure can't be a compile-type error.

往事风中埋 2024-08-10 21:01:58

我认为没有人声称常量正确性是“必要的”。但话又说回来,课程也不是真正必要的,不是吗?这同样适用于命名空间、异常……你明白了。

常量正确性有助于在编译时捕获错误,这就是它有用的原因。

I don't think anybody claims const-correctness is "necessary". But again, classes are not really necessary either, are they? The same goes for namespaces, exceptions,... you get the picture.

Const-correctness helps catch errors at compile time, and that's why it is useful.

一城柳絮吹成雪 2024-08-10 21:01:58

好吧,我花了六年的时间才真正理解,但现在我终于可以回答我自己的问题了。

C++ 具有“常量正确性”而 Java、C# 等没有的原因是 C++ 只支持值类型,而这些其他语言只支持或至少默认为 参考类型

让我们看看 C# 这种默认使用引用类型的语言在涉及值类型时如何处理不变性。假设您有一个可变值类型,以及另一个具有该类型只读字段的类型:

struct Vector {
    public int X { get; private set; }
    public int Y { get; private set; }
    public void Add(int x, int y) {
        X += x;
        Y += y;
    }
}

class Foo {
    readonly Vector _v;
    public void Add(int x, int y) => _v.Add(x, y);
    public override string ToString() => $"{_v.X} {_v.Y}";
}

void Main()
{
    var f = new Foo();
    f.Add(3, 4);
    Console.WriteLine(f);
}

这段代码应该做什么?

  1. 编译失败
  2. print "3, 4"
  3. print "0, 0"

答案是#3。 C# 尝试通过在对象的一次性副本上调用 Add 方法来遵循“只读”关键字。是的,这很奇怪,但是它还有什么其他选择呢?如果它调用原始 Vector 上的方法,则对象将发生更改,从而违反了字段的“只读”特性。如果编译失败,那么只读值类型成员就毫无用处,因为您无法调用它们的任何方法,因为担心它们可能会更改对象。

如果我们能够标记哪些方法可以在只读实例上安全调用就好了……等等,这正是 C++ 中的 const 方法!

C# 不关心 const 方法,因为我们在 C# 中使用的值类型不多;我们只是避免可变值类型(并将它们声明为“邪恶”,请参阅 12)。

此外,引用类型不会遇到此问题,因为当您将引用类型变量标记为只读时,只读的是引用,而不是对象本身。这对于编译器来说很容易强制执行,它可以将任何赋值标记为编译错误,初始化除外。如果您使用的只是引用类型,并且所有字段和变量都是只读的,那么您可以以很少的语法成本获得无处不在的不变性。 F# 的工作原理完全是这样的。 Java 通过不支持用户定义的值类型来避免这个问题。

C++ 没有“引用类型”的概念,只有“值类型”的概念(在 C# 术语中);其中一些值类型可以是指针或引用,但与 C# 中的值类型一样,它们都不拥有自己的存储空间。如果 C++ 在其类型上处理“const”,就像 C# 在值类型上处理“readonly”一样,那么如上面的示例所示,这将非常令人困惑,更不用说与复制构造函数的令人讨厌的交互了。

因此,C++ 不会创建一次性副本,因为这会带来无尽的痛苦。它也不禁止您调用成员上的任何方法,因为那时该语言就不是很有用了。但它仍然希望有一些“只读”或“常量”的概念。

C++ 尝试找到一种中间方法,让您标记哪些方法可以安全地调用 const 成员,然后它相信您的标记是忠实且准确的,并直接在原始对象上调用方法。这并不完美——它很冗长,而且你可以随意违反常量——但它可以说比所有其他选项都要好。

Well, it will have taken me 6 years to really understand, but now I can finally answer my own question.

The reason C++ has "const-correctness" and that Java, C#, etc. don't, is that C++ only supports value types, and these other languages only support or at least default to reference types.

Let's see how C#, a language that defaults to reference types, deals with immutability when value types are involved. Let's say you have a mutable value type, and another type that has a readonly field of that type:

struct Vector {
    public int X { get; private set; }
    public int Y { get; private set; }
    public void Add(int x, int y) {
        X += x;
        Y += y;
    }
}

class Foo {
    readonly Vector _v;
    public void Add(int x, int y) => _v.Add(x, y);
    public override string ToString() => $"{_v.X} {_v.Y}";
}

void Main()
{
    var f = new Foo();
    f.Add(3, 4);
    Console.WriteLine(f);
}

What should this code do?

  1. fail to compile
  2. print "3, 4"
  3. print "0, 0"

The answer is #3. C# tries to honor your "readonly" keyword by invoking the method Add on a throw-away copy of the object. That's weird, yes, but what other options does it have? If it invokes the method on the original Vector, the object will change, violating the "readonly"-ness of the field. If it fails to compile, then readonly value type members are pretty useless, because you can't invoke any methods on them, out of fear they might change the object.

If only we could label which methods are safe to call on readonly instances... Wait, that's exactly what const methods are in C++!

C# doesn't bother with const methods because we don't use value types that much in C#; we just avoid mutable value types (and declare them "evil", see 1, 2).

Also, reference types don't suffer from this problem, because when you mark a reference type variable as readonly, what's readonly is the reference, not the object itself. That's very easy for the compiler to enforce, it can mark any assignment as a compilation error except at initialization. If all you use is reference types and all your fields and variables are readonly, you get immutability everywhere at little syntactic cost. F# works entirely like this. Java avoids the issue by just not supporting user-defined value types.

C++ doesn't have the concept of "reference types", only "value types" (in C#-lingo); some of these value types can be pointers or references, but like value types in C#, none of them own their storage. If C++ treated "const" on its types the way C# treats "readonly" on value types, it would be very confusing as the example above demonstrates, nevermind the nasty interaction with copy constructors.

So C++ doesn't create a throw-away copy, because that would create endless pain. It doesn't forbid you to call any methods on members either, because, well, the language wouldn't be very useful then. But it still wants to have some notion of "readonly" or "const-ness".

C++ attempts to find a middle way by making you label which methods are safe to call on const members, and then it trusts you to have been faithful and accurate in your labeling and calls methods on the original objects directly. This is not perfect - it's verbose, and you're allowed to violate const-ness as much as you please - but it's arguably better than all the other options.

以歌曲疗慰 2024-08-10 21:01:58

const 是表达某些事物的一种方式。如果您认为表达它很重要,那么它在任何语言中都会很有用。它们没有这个功能,因为语言设计者没有发现它们有用。我认为,如果该功能存在,那么它也会很有用。

我觉得它就像 Java 中的 throw 规范。如果您喜欢它们,您可能会喜欢其他语言的版本。但其他语言的设计者并不认为它那么重要。

const is a way for you to express something. It would be useful in any language, if you thought it was important to express it. They don't have the feature, because the language designers didn't find them useful. If the feature was there, it would be about as useful, I think.

I kind of think of it like throw specifications in Java. If you like them, you would probably like them in other languages. But the designers of the other languages didn't think it was that important.

意中人 2024-08-10 21:01:58

你是对的,常量正确性是不必要的。当然,您可以在不使用 const 关键字的情况下编写所有代码并让代码正常工作,就像在 Java 和 Python 中一样。

但如果您这样做,您将不再获得编译器在检查 const 违规方面的帮助。编译器在编译时告诉您的错误现在只能在运行时发现(如果有的话),因此需要更长的时间来诊断和修复。

因此,从长远来看,试图颠覆或避免常量正确性特性只会让事情变得更加困难。

You're right, const-correctness isn't necessary. You can certainly write all your code without the const keyword and get things to work, just as you do in Java and Python.

But if you do that, you'll no longer get the compiler's help in checking for const violations. Errors that the compiler would have told you about at compile-time will now be found only at run-time, if at all, and therefore will take you longer to diagnose and fix.

Therefore, trying to subvert or avoid the const-correctness feature is just making things harder for yourself in the long run.

淡淡離愁欲言轉身 2024-08-10 21:01:58

编程是用最终由计算机处理的语言进行编写,但这既是与计算机和同一项目中的其他程序员进行通信的一种方式。当您使用一种语言时,您受到可以用它表达的概念的限制,而 const 只是您可以用来描述您的问题和解决方案的另一个概念。

恒定性使您能够从设计板到代码清楚地表达其他语言所缺乏的概念。当你来自一种没有它的语言时,你可能会对一个你从未使用过的概念感到困惑——如果你以前从未使用过它,它会有多重要?

语言和思想是紧密结合的。你只能用你所说的语言表达你的想法,但语言也会改变你的思维方式。事实上,您使用的语言中没有 const 关键字,这意味着您已经找到了相同问题的其他解决方案,并且这些解决方案对您来说似乎很自然。

在这个问题中,您认为您可以提供一个非变异接口,可供不需要更改对象内容的函数使用。如果你想一想,这句话告诉你为什么 const 是你想要使用的概念。
必须定义一个非变异接口并在您的类中实现它是为了解决您无法用您的语言表达该概念的事实。

恒定性允许您用编译器(和其他程序员)可以理解的语言表达这些概念。您正在对如何处理您收到的参数、您存储的参考资料做出妥协,或者定义您的班级用户可以对您提供的参考资料进行哪些操作的限制。几乎每个非平凡类都可以具有由属性表示的状态,并且在许多情况下必须保留一些不变量。该语言允许您定义提供对某些内部数据的访问的函数,同时限制对只读视图的访问,以保证外部代码不会破坏您的不变量。

这是我在转向其他语言时更想念的概念。考虑一个场景,您有一个类 C,其中有一个类型 A 的属性 a,该属性必须对外部代码可见(您的类的用户必须能够查询 a 的某些信息)。如果 A 的类型有任何变异操作,那么为了防止用户代码更改内部状态,您必须创建 a 的副本并返回它。该类的程序员必须意识到必须执行复制并且必须执行(可能昂贵的)复制。另一方面,如果您可以用语言表达常量,则可以仅返回对对象的常量引用(实际上是对对象的常量视图的引用)并仅返回内部元素。这将允许用户代码调用被检查为非变异的对象的任何方法,从而保留您的类不变量。

持续性的问题/优点完全取决于观点,那就是它是病毒式的。当您提供对对象的常量引用时,只能调用那些标记为非变异的方法,并且您必须告诉编译器哪些方法具有此属性。当您声明方法常量时,您是在告诉编译器调用该方法的用户代码将保留对象状态。当您定义(实现)具有常量签名的方法时,编译器会提醒您您的承诺,并且实际上要求您不要在内部修改数据。

该语言使您能够告诉编译器您的方法的属性,您无法以任何其他方式表达,同时,编译器会告诉您何时不符合您的设计并尝试修改数据。

在这种情况下,const_cast<>永远不应该使用,因为结果可能会将您带入未定义行为的领域(从语言的角度来看:对象可能位于只读内存中,从程序的角度来看:您可能会破坏其他类)。当然,如果您阅读了 C++FAQ lite,您就已经知道了。

附带说明一下,当您处理引用(在 C++ 引用或指针中)时,Java 中的 Final 关键字实际上与 C++ 中的 const 关键字无关。 Final 关键字修改它所引用的局部变量,无论是基本类型还是引用,但不是所引用对象的修饰符。也就是说,您可以通过最终引用调用变异方法,从而提供所引用对象状态的更改。在 C++ 中,引用始终是常量(只能在构造期间将它们绑定到对象/变量),并且 const 关键字修改用户代码处理引用对象的方式。 (对于指针,您可以对数据和指针使用 const 关键字:X const * const 声明一个指向常量 X 的常量指针

Programming is writing in a language that will be ultimately processed by the computer, but that is both a way of communicating with the computer and other programmers in the same project. When you use a language, you are restricted to the concepts that can be expressed in it, and const is just one more concept you can use to describe your problem, and your solution.

Constantness enables you to express clearly from the design board to the code one concept that other languages lack. As you come from a language that does not have it, you may seem puzzled by a concept you have never used --if you never used it before, how important can it be?

Language and thought are tightly coupled. You can only express your thoughts in the language you speak, but the language also changes the way you think. The fact that you did not have the const keyword in the languages you worked with implies that you have already found other solutions to the same problems, and those solutions are what seems natural to you.

In the question you argued that you can provide a non mutating interface that can be used by functions that do not need to change the contents of the objects. If you think about it for a second, this same sentence is telling you why const is a concept you want to work with.
Having to define a non-mutating interface and implement it in your class is a work around the fact that you cannot express that concept in your language.

Constantness allows you to express those concepts in a language that the compiler (and other programers) can understand. You are establishing a compromise on what you will do with the parameters you receive, the references you store, or defining limits on what the users of your class are allowed to do with the references you provide. Pretty much each non-trivial class can have a state represented by attributes, and in many cases there are invariants that must be kept. The language lets you define functions that offer access to some internal data while at the same time limits the access to a read-only view that guarantees no external code will break your invariants.

This is the concept I miss more when moving to other languages. Consider an scenario where you have a class C that has among others an attribute a of type A that must be visible to external code (users of your class must be able to query for some information on a). If the type of A has any mutating operation, then to keep user code from changing your internal state, you must create a copy of a and return it. The programmer of the class must be aware that a copy must be performed and must perform the (possibly expensive) copy. On the other hand, if you could express constantness in the language, you could just return a constant reference to the object (actually a reference to a constant view of the object) and just return the internal element. This will allow the user code to call any method of the object that is checked as non-mutating, thus preserving your class invariants.

The problem/advantage, all depends on the point of view, of constantness is that it is viral. When you offer a constant reference to an object, only those methods flagged as non-mutating can be called, and you must tell the compiler which of the methods have this property. When you declare a method constant, you are telling the compiler that user code that calls that method will keep the object state. When you define (implement) a method that has a constant signature, the compiler will remind you of your promise and actually require that you do not internally modify the data.

The language enables you to tell the compiler properties of your methods that you cannot express any other way, and at the same time, the compiler will tell you when you are not complying with your design and try to modify the data.

In this context, const_cast<> should never be used, as the results can take you into the realm of undefined behavior (both from a language point of view: the object could be in read-only memory, and from a program point of view: you might be breaking invariants in other classes). But that, of course, you already know if you read the C++FAQ lite.

As a side note, the final keyword in Java has really nothing to do with the const keyword in C++ when you are dealing with references (in C++ references or pointers). The final keyword modifies the local variable to which it refers, whether a basic type or a reference, but is not a modifier of the referred object. That is, you can call mutating methods through a final reference and thus provide changes in the state of the object referred. In C++, references are always constant (you can only bind them to an object/variable during construction) and the const keyword modifies how the user code can deal with the referred object. (In case of pointers, you can use the const keyword both for the datum and the pointer: X const * const declares a constant pointer to a constant X)

冰魂雪魄 2024-08-10 21:01:58

如果您正在为带有 FLASH 或 ROM 中数据的嵌入式设备编写程序,那么没有 const 正确性就无法生存。它使您能够控制不同类型内存中数据的正确处理。

If you are writing programs for embedded devices with data in FLASH or ROM you can't live without const-correctness. It gives you the power to control the correct handling of data in different types of memory.

掌心的温暖 2024-08-10 21:01:58

您还想在方法中使用 const 以利用返回值优化。请参阅 Scott Meyers 更有效的 C++ 第 20 条。

You want to use const in methods as well in order to take advantage of return value optimization. See Scott Meyers More Effective C++ item 20.

梦亿 2024-08-10 21:01:58

演讲和视频来自 < em>Herb Sutter解释了 const 关于线程安全的新内涵。

常量 以前可能不需要您太担心,但在 C++11 中,如果您想编写线程安全的代码,您需要了解 const可变

This talk and video from Herb Sutter explains the new connotations of const with regards to thread-safety.

Constness might not have been something you had to worry about too much before but with C++11 if you want to write thread-safe code you need to understand the significance of const and mutable

回首观望 2024-08-10 21:01:58

在 C、Java 和 C# 中,您可以通过查看调用站点来判断传递的对象是否可以由函数修改:

  • 在 Java 中,您知道它绝对可以。
  • 在 C 语言中,您知道只有存在“&”或等效符号时才可以。
  • 在 C# 中,您也需要在调用站点说“ref”。

一般来说,在 C++ 中你无法分辨这一点,因为非常量引用调用看起来与按值传递相同。拥有 const 引用允许您设置和强制执行 C 约定。

这会对调用函数的任何代码的可读性产生相当大的影响。这可能足以证明语言功能的合理性。

In C, Java and C# you can tell by looking at the call site if a passed object can be modified by a function:

  • in Java you know it definitely can be.
  • in C you know it only can be if there is a '&', or equivalent.
  • in c# you need to say 'ref' at the call site too.

In C++ in general you can't tell this, as a non-const reference call looks identical to pass-by-value. Having const references allows you to set up and enforce the C convention.

This can make a fairly major difference in readability of any code that calls functions. Which is probably enough to justify a language feature.

你的背包 2024-08-10 21:01:58

Anders Hejlsberg(C# 架构师):...如果您声明一个采用非 const Bla 的方法,则无法向其传递 const Bla。所以现在你被困住了。所以你逐渐需要所有非 const 的东西的 const 版本,最终你会得到一个影子世界。

再说一遍:如果您开始对某些方法使用“const”,您通常会被迫在大多数代码中使用它。但是,在代码中维护(键入、在缺少某些 const 时重新编译等)const 正确性所花费的时间似乎比修复因根本不使用 const 正确性而导致的可能(非常罕见)的问题要多。因此,现代语言(如 Java、C#、Go 等)缺乏 const 正确性支持可能会导致相同代码质量的开发时间略有减少。

自 1999 年以来,Java Community Process 中就存在用于实现 const 正确性的增强请求票证,但由于上述“const 污染”以及兼容性原因而于 2005 年关闭:https://bugs.java.com/bugdatabase/view_bug?bug_id=4211070

虽然 C# 语言没有 const 正确性结构,但可能会出现类似的功能很快就会在 .NET Framework 的“Microsoft 代码契约”(库 + 静态分析工具)中使用 [Pure] 和 [Immutable] 属性:C# 是否(或将会)包含副作用验证功能?

Anders Hejlsberg (C# architect): ... If you declare a method that takes a non-const Bla, you can't pass it a const Bla. So now you're stuck. So you gradually need a const version of everything that isn't const, and you end up with a shadow world.

So again: if you started to use "const" for some methods you usually forced to use this in most of your code. But the time spent for maintaining (typing, recompiling when some const is missing, etc.) of const-correctness in code seems greater than for fixing of possible (very rare) problems caused by not using of const-correctness at all. Thus lack of const-correctness support in modern languages (like Java, C#, Go, etc.) might result in slightly reduced development time for the same code quality.

An enhancement request ticket for implementing const correctness existed in the Java Community Process since 1999, but was closed in 2005 due to above mentioned "const pollution" and also compatibility reasons: https://bugs.java.com/bugdatabase/view_bug?bug_id=4211070

Although C# language has no const correctness construct but similar functionality possibly will appear soon in "Microsoft Code Contracts" (library + static analysis tools) for .NET Framework by using [Pure] and [Immutable] attributes: Does (or will) C# include features for side-effects verification?

南城旧梦 2024-08-10 21:01:58

事实上,无论如何,这不……不完全是。

在其他语言中,尤其是函数式或混合语言,如 Haskell、D、Rust 和 Scala,您有可变性的概念:变量可以是可变的,也可以是不可变的,并且默认情况下通常是不可变的。

这可以让你(和你的编译器/解释器)更好地推理函数:如果你知道一个函数只接受不可变的参数,那么你就知道该函数不是改变你的变量并导致错误的函数。

C 和 C++ 使用 const 做类似的事情,只不过它的保证不太牢固:不强制执行不变性;调用堆栈下方的函数可能会放弃常量性并改变数据,但这将是故意违反 API 契约的行为。因此,意图或最佳实践是让它像其他语言中的不变性一样工作。

尽管如此,C++ 11 现在有了一个实际的 mutable 关键字,以及更有限的 const 关键字。

Actually, it's not... not entirely, anyway.

In other languages, especially functional or hybrid languages, like Haskell, D, Rust, and Scala, you have the concept of mutability: variables can be mutable, or immutable, and are usually immutable by default.

This lets you (and your compiler/interpreter) reason better about functions: if you know that a function only takes immutable arguments, then you know that function isn't the one that's mutating your variable and causing a bug.

C and C++ do something similar using const, except that it's a much less firm guarantee: the immutability isn't enforced; a function further down the call stack could cast away the constness, and mutate your data, but that would be a deliberate violation of the API contract. So the intention or best practice is for it to work quite like immutability in other languages.

All that said, C++ 11 now has an actual mutable keyword, alongside the more limited const keyword.

请你别敷衍 2024-08-10 21:01:58

C++ 中的 const 关键字(应用于参数和类型声明)是为了防止程序员在此过程中失去大脚趾并失去整条腿。

基本思想是将某些内容标记为“无法修改”。 const 类型无法修改(默认情况下)。 const 指针不能指向内存中的新位置。很简单,对吧?

好吧,这就是 const 正确性的用武之地。以下是使用 const 时可能出现的一些组合:

const 变量
表示变量名标注的数据不能修改。

指向 const 变量的指针
意味着指针可以修改,但数据本身不能修改。

指向变量的 const 指针
意味着无法修改指针(指向新的内存位置),但可以修改指针指向的数据

指向 const 变量的 const 指针
意味着指针及其指向的数据都不能被修改。

你知道那里有些事情是多么愚蠢吗?这就是为什么当您使用 const 时,正确标记哪个 const 很重要。

关键是这只是一个编译时黑客。标签只是告诉编译器如何解释指令。如果你放弃 const,你就可以做任何你想做的事。但是您仍然需要调用具有 const 要求且类型正确转换的方法。

The const keyword in C++ (as applied to parameters and type declarations) is an attempt to keep programmers from shooting off their big toe and taking out their whole leg in the process.

The basic idea is to label something as "cannot be modified". A const type can't be modified (by default). A const pointer can't point to a new location in memory. Simple, right?

Well, that's where const correctness comes in. Here are some of the possible combinations you can find yourself in when you use const:

A const variable
Implies that the data labeled by the variable name cannot be modified.

A pointer to a const variable
Implies that the pointer can be modified, but the data itself cannot.

A const pointer to a variable
Implies that the pointer cannot be modified (to point to a new memory location), but that the data to which the pointer points can be modified.

A const pointer to a const variable
Implies that neither the pointer nor the data to which it points can be modified.

Do you see how some things can be goofy there? That's why when you use const, it's important to be correct in which const you are labeling.

The point is that this is just a compile-time hack. The labeling just tells the compiler how to interpret instructions. If you cast away from const, you can do whatever you want. But you'll still have to call methods that have const requirements with types that are cast appropriately.

扮仙女 2024-08-10 21:01:58

例如,您有一个函数:

void const_print(const char* str)
{
    cout << str << endl;
}

另一种方法

void print(char* str)
{
    cout << str << endl;
}

在 main 中:

int main(int argc, char **argv)
{
    const_print("Hello");
    print("Hello");        // syntax error
}

这是因为“hello”是一个 const char 指针,所以(C 风格)字符串被放入只读存储器中。
但当程序员知道该值不会改变时,它总体上很有用。因此得到编译器错误而不是分段错误。
就像在不需要的赋值中一样:

const int a;
int b;
if(a=b) {;} //for mistake

因为左操作数是 const int。

For example you have a funcion:

void const_print(const char* str)
{
    cout << str << endl;
}

Another method

void print(char* str)
{
    cout << str << endl;
}

In main:

int main(int argc, char **argv)
{
    const_print("Hello");
    print("Hello");        // syntax error
}

This because "hello" is a const char pointer, the (C-style) string is put in read only memory.
But it's useful overall when the programmer knows that the value will not be changed.So to get a compiler error instead of a segmentation fault.
Like in non-wanted assignments:

const int a;
int b;
if(a=b) {;} //for mistake

Since the left operand is a const int.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文