向我推销常识正确性

那么,为什么总是建议尽可能频繁地使用 const 呢?在我看来,使用 const 比使用 C + + 更让人头疼。不过话说回来,我是从 Python 的角度出发的: 如果你不想改变什么,那就不要改变它。因此,这里有几个问题:

  1. 似乎每次我标记一些东西为 const,我得到一个错误,并不得不改变一些其他的函数在某处也是 const。然后这导致我不得不在其他地方更改 另一个函数。经验丰富了就容易了吗?

  2. 使用 const 真的的好处是否足以弥补这个问题?如果您不打算更改对象,为什么不直接编写不更改对象的代码呢?

我应该指出,在这一点上,我最关注的是出于正确性和可维护性的目的使用 const 的好处,尽管了解其性能含义也很不错。

32094 次浏览

下面是一段代码,它有一个常见的错误,常数正确性可以保护您不受这个错误的影响:

void foo(const int DEFCON)
{
if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
{
fire_missiles();
}
}

在 c + + 中有一篇关于 const 的很好的文章 给你。这是一个相当直接的意见,但希望它有所帮助。

当您最初编写代码时,它不适合您。对于正在查看类或接口中的方法声明的其他人(或者几个月后的您)来说,这样做是为了了解它的功能。不修改对象是从中收集到的重要信息。

这是关于“常量正确性”的权威文章: https://isocpp.org/wiki/faq/const-correctness

简而言之,使用 const 是很好的做法,因为..。

  1. 它可以保护您不会意外地更改不应该更改的变量,
  2. 它可以保护您不会做出意外的可变分配,并且
  3. 编译器可以对其进行优化

    if( x = y ) // whoops, meant if( x == y )
    

At the same time, the compiler can generate more efficient code because it knows exactly what the state of the variable/function will be at all times. If you are writing tight C++ code, this is good.

You are correct in that it can be difficult to use const-correctness consistently, but the end code is more concise and safer to program with. When you do a lot of C++ development, the benefits of this quickly manifest.

const可以帮助您隔离那些在您背后“改变事情”的代码。因此,在类中,将所有不更改对象状态的方法标记为 const。这意味着该类的 const实例将不再能够调用任何非 const方法。这样,您就可以避免意外地调用可以更改对象的功能。

而且,const是重载机制的一部分,因此您可以有两个具有相同签名的方法,但是一个具有 const,另一个没有。具有 const的一个用于 const引用,另一个用于非 const引用。

例如:

#include <iostream>


class HelloWorld {
bool hw_called;


public:
HelloWorld() : hw_called(false) {}


void hw() const {
std::cout << "Hello, world! (const)\n";
// hw_called = true;  <-- not allowed
}


void hw() {
std::cout << "Hello, world! (non-const)\n";
hw_called = true;
}
};


int
main()
{
HelloWorld hw;
HelloWorld* phw1(&hw);
HelloWorld const* phw2(&hw);


hw.hw();    // calls non-const version
phw1->hw(); // calls non-const version
phw2->hw(); // calls const version
return 0;
}

理论上,我喜欢常规正确性。每次我尝试在实践中严格应用它时,它最终都会崩溃,const _ cast 开始使代码变得丑陋。

也许这只是我使用的设计模式,但常量最终总是过于宽泛。

例如,想象一个简单的数据库引擎... 它有模式对象、表、字段等。用户可能有一个“ const Table”指针,这意味着他们不允许修改表模式本身... ... 但是如何处理与表相关的数据呢?如果 Insert ()方法被标记为 const,那么它必须在内部抛弃常量才能实际操作数据库。如果它没有被标记为 const,那么它就不能防止调用 AddField 方法。

也许答案是根据常量需求将类分开,但这往往会使设计复杂化,而不是我希望它带来的好处。

当您使用“ const”关键字时,您正在为您的类指定另一个接口。有一个包含所有方法的接口,以及一个只包含 const 方法的接口。显然,这使您可以限制对某些您不希望更改的内容的访问。

是的,随着时间的推移会变得越来越容易。

好像每次我标记的时候 我得到一个错误 必须改变一些其他的功能 有个地方可以去,然后这个 让我不得不改变另一个 在别的地方发挥作用 这样就容易多了 经验?

根据经验,这完全是个神话。当不常量正确的代码处于常量正确的代码中时,当然会发生这种情况。如果你从一开始就设计常数正确,这应该永远不会成为一个问题。如果你做了一个 const,然后其他的东西没有被编译,编译器会告诉你一些非常重要的东西,你应该花时间去修复它 适当地

我的理念是,如果您打算使用一种带有编译时检查的吹毛求疵的语言,那么就尽可能好地利用它。const是一个编译器强制的方式来传达你的 平均数... 它比注释或 doxygen 更好。你付出了代价,为什么不得出价值呢?

Const 是您作为开发人员所做出的承诺,并且在执行过程中获得了编译器的帮助。

我之所以这么说是因为:

  • 它向函数的客户端传达您不会更改变量或对象的信息
  • 通过常量引用接受参数可以提高通过引用传递的效率,同时保证了通过值传递的安全性。
  • 以常数正确的方式编写接口将使客户端能够使用它们。如果您编写接口以接受非常量引用,那么使用常量的客户端将需要抛弃常量才能与您一起工作。如果接口接受非 const char * ,而客户机使用 std: : string,那么这种情况尤其令人烦恼,因为只能从它们获得 const char * 。
  • 使用 const 将使编译器保持诚实,这样您就不会错误地更改不应该更改的内容。

对于嵌入式编程,在声明全局数据结构时使用 const可以节省大量 RAM,因为它可以使常量数据位于 ROM 或 flash 中,而无需在引导时复制到 RAM。

在日常编程中,仔细使用 const可以帮助您避免编写崩溃或行为不可预测的程序,因为它们试图修改字符串文字和其他常量全局数据。

在大型项目中与其他程序员一起工作时,正确使用 const有助于防止其他程序员扼杀您。

假设您在 Python 中有一个变量。您知道您不是 假设来修改它。如果您不小心这样做了呢?

C + + 给了你一种保护自己的方法,防止你意外地做一些你一开始就不应该做的事情。技术上来说,你可以绕过它,但你必须投入额外的工作,以拍摄自己。

按照下面的代码,您也可以使用 const 给编译器提示

#include <string>


void f(const std::string& s)
{


}
void x( std::string& x)
{
}
void main()
{
f("blah");
x("blah");   // won't compile...
}

没有常量的 C + + 编程就像没有系安全带的驾驶。

每次上车都要系上安全带是一件痛苦的事情,365天中有364天你会安全到达。

唯一的区别是,当你的车出了问题,你会立即感觉到它,而编程没有常量,你可能不得不搜索两个星期,什么造成了崩溃,结果发现,你无意中搞砸了一个函数参数,你通过非常量引用的效率。

如果您严格地使用 const,您会惊讶地发现大多数函数中的实变量非常少。通常不超过一个循环计数器。如果你的代码达到了那个程度,你会有一种温暖的感觉... ... 编译验证... ... 函数式编程的领域就在附近... ... 你现在几乎可以触摸到它了... ..。

Const 正确性是从一开始就需要做的事情之一。正如您所发现的,以后再添加它是一件非常痛苦的事情,特别是当您正在添加的新函数和已经存在的旧的不符合常数的函数之间存在很多依赖关系时。

在我编写的许多代码中,这确实是值得付出努力的,因为我们倾向于大量使用组合:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

如果我们没有常量正确性,那么你将不得不求助于返回复杂对象的值,以确保没有人在背后操纵类 b 的内部状态。

简而言之,常量正确性是一种防御性编程机制,可以让你在路上免受痛苦。