按照const的正确性卖给我
那么为什么它总是推荐尽可能经常使用const? 在我看来,使用const比在C ++中的帮助更加痛苦。 但是再次,我从python的angular度来看这个问题:如果你不想改变某些东西,不要改变它。 所以说,这里有几个问题:
-
这似乎是每次我标记为const的东西,我得到一个错误,不得不改变一些其他函数的地方是常量。 然后这导致我不得不在其他地方改变另一个function。 这是什么东西,随着经验变得更容易?
-
使用const的好处真的足以弥补麻烦吗? 如果你不打算改变一个对象,为什么不写一些不改变它的代码呢?
我应该注意到,在这个时候,我最关注的是使用const来实现正确性和可维护性的好处,但是对性能的影响也是很好的。
这是关于“const正确性”的权威性文章: https : //isocpp.org/wiki/faq/const-correctness 。
简而言之,使用const是很好的做法,因为…
- 它可以防止意外更改无意更改的variables,
- 它可以保护你免于意外的variables赋值
-
编译器可以优化它。 例如,你受到保护
if( x = y ) // whoops, meant if( x == y )
与此同时,编译器可以生成更高效的代码,因为它确切地知道variables/函数的状态。 如果你正在写紧密的C ++代码,这是好的。
你是正确的,可能难以一致地使用const正确性,但是最终的代码更简洁和更安全的编程。 当你做大量的C ++开发时,这个好处很快就会体现出来。
这里有一段代码有一个常见的错误,const正确性可以保护你:
void foo(const int DEFCON) { if (DEFCON = 1) //< FLAGGED AS COMPILER ERROR! WORLD SAVED! { fire_missiles(); } }
这似乎是每次我标记为const的东西,我得到一个错误,不得不改变一些其他函数的地方是常量。 然后这导致我不得不在其他地方改变另一个function。 这是什么东西,随着经验变得更容易?
从经验来看,这完全是一个神话。 当非常量正确的坐标与正确的代码,当然会发生。 如果你从头开始deviseconst-correct,这永远不会是一个问题。 如果你做了一些const,然后其他的东西不能编译,编译器会告诉你一些非常重要的东西,你应该花时间来正确地修复它。
最初编写代码时不适合你。 这是给别人的(或者几个月之后)谁正在查看类或接口中的方法声明来看看它是做什么的。 不修改对象是从中收集的重要信息。
const是你作为一个开发人员所作的承诺,并且强化编译器的帮助。
我是常数正确的理由:
- 它与你的函数的客户端通信,你不会改变variables或对象
- 通过const引用接受参数,可以提供通过参考传递的效率以及传递值的安全性。
- 把你的接口写成const正确将使客户端能够使用它们。 如果你编写你的接口来接受非const引用,那么使用const的客户端需要将const转换为与你一起工作。 如果你的接口接受非const char *,并且你的客户端使用std :: strings,这是特别恼人的,因为你只能从它们中获得一个const char *。
- 使用const会使编译器保持诚实,所以你不会错误地改变不应该改变的东西。
如果你严格使用const,你会惊讶于大多数函数中几乎没有实际的variables。 通常不超过一个循环计数器。 如果你的代码达到了这一点,你会得到一种温暖的感觉……编译validation…函数式编程的领域是在附近…你几乎可以触摸它…
没有const的编程C ++就像没有安全带的驾驶一样。
每踩一次车都要戴上安全带是一件很痛苦的事情,在365天内你会安全到达的。
唯一的区别是,当你遇到汽车麻烦的时候,你会马上感觉到它,而在没有const的情况下编程,你可能需要search两个星期导致这个崩溃的原因,只是发现你无意间弄乱了一个函数的参数你通过非const引用来提高效率。
我的理念是,如果你要使用挑剔的语言编译时间检查,而不是充分利用它,你可以。 const
是一个编译器强制传达你的意思的方式 …它比评论或doxygen永远是好的。 你付出的代价,为什么不推导价值?
对于embedded式编程,在声明全局数据结构时明智地使用const
可以通过使常量数据位于ROM或闪存中而不需要在启动时复制到RAM来节省大量的RAM。
在日常编程中,小心使用const
可以帮助您避免编写出现崩溃或行为不可预测的程序,因为它们试图修改string文字和其他常量全局数据。
在大型项目中与其他程序员一起工作时,正确使用const
有助于防止其他程序员对您进行限制。
const
可以帮助你隔离背后的“改变事物”的代码。 所以,在一个类中,你要把所有不改变对象状态的方法标记为const
。 这意味着该类的const
实例将不再能够调用任何非const
方法。 这样,您可以防止意外调用可以改变对象的function。
此外, 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正确函数之间存在很多依赖关系的时候。
在我编写的很多代码中,它的确值得付出努力,因为我们倾向于使用合成:
class A { ... } class B { A m_a; const A& getA() const { return m_a; } };
如果我们不具有常数正确性,那么你将不得不求助于按照价值返回复杂对象,以保证自己没有人在背后操纵B类的内部状态。
简而言之,常量正确性是一种防御性的编程机制,可以帮助您免于痛苦。
假设你在Python中有一个variables。 你知道你不应该修改它。 如果你不小心做了什么?
C ++为您提供了一种保护自己免于意外执行您本来不应该做的事情的方法。 从技术上讲,无论如何你都可以绕过它,但是你必须投入额外的工作来拍摄自己。
这里有一个很好的关于const在c ++中的文章。 它是一个非常直接的意见,但希望它有助于一些。
当你使用“const”关键字时,你正在为你的类指定另一个接口。 有一个包含所有方法的接口和一个只包含const方法的接口。 显然这可以让你限制访问一些你不想改变的东西。
是的,随着时间的推移它变得更容易了。
我喜欢const正确性…在理论上。 每次我试图在实践中严格地应用它,它最终都会崩溃,const_cast开始蠕变,使代码变得丑陋。
也许这只是我所使用的devise模式,但是const总是最终会变得太粗糙。
例如,设想一个简单的数据库引擎…它具有模式对象,表,字段等。用户可能有一个“const表”指针,这意味着他们不允许修改表模式本身…但是操纵与表关联的数据? 如果Insert()方法被标记为const,那么在内部它必须将常量转换为实际操作数据库。 如果它没有标记为const,那么它不能防止调用AddField方法。
也许答案是根据常数的要求将课程拆分,但这样做往往会使devise复杂化,而不是我想要带来的好处。
你可以给const编译器提示以及….按照下面的代码
#include <string> void f(const std::string& s) { } void x( std::string& x) { } void main() { f("blah"); x("blah"); // won't compile... }
也没有const正确性,你不能通过const引用传递参数,这可能导致更多的复制。 通过(非const)引用不是溶剂,因为非const引用不能绑定到临时对象。