卖我的正确性

Jas*_*ker 121 c++ const-correctness

那么为什么总是建议尽可能经常使用const呢?在我看来,使用const可能比C++中的帮助更痛苦.但话说回来,我是从python的角度来看这个:如果你不想改变某些东西,不要改变它.所以说,这里有几个问题:

  1. 似乎每次我将某些东西标记为const时,我都会收到错误,并且必须将某些其他函数更改为const.然后这导致我必须在其他地方更改另一个功能.这是通过经验变得更容易吗?

  2. 使用const的好处真的足以弥补麻烦吗?如果您不打算更改对象,为什么不编写不会更改它的代码?

我应该注意到,在这个时间点,我最关注的是使用const来实现正确性和可维护性的好处,尽管了解性能影响也很好.

Jor*_*mer 151

这是关于"const correctness"的权威性文章:https://isocpp.org/wiki/faq/const-correctness.

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

  1. 它可以保护您免于意外更改无意更改的变量,
  2. 它可以保护您免受意外变量分配的影响
  3. 编译器可以优化它.例如,您受到保护

    if( x = y ) // whoops, meant if( x == y )
    
    Run Code Online (Sandbox Code Playgroud)

同时,编译器可以生成更高效的代码,因为它确切地知道变量/函数的状态.如果您正在编写严格的C++代码,这很好.

你是正确的,因为一致地使用const-correctness可能很困难,但最终代码更简洁,更安全.当你做很多C++开发时,这种好处很快就体现出来了.

  • 从C++ 11开始,标准库还假定`const`表示线程安全并以这种方式处理您自己的代码,这样可以更容易地检查可能的多线程问题,并且是为API用户提供API保证的简单方法. (4认同)
  • 当然.`const`变量*可以*提高速度,因为编译器可以生成更优的代码,因为它知道变量的完整意图和使用.你会注意到差异吗?那么,这对你的申请是有争议的.就并发性而言,const变量是只读的,这意味着不需要对这些变量进行排它锁,因为值总是相同的. (3认同)
  • 对我来说,const正确性的最大增值之一是,当指针引用从未被函数突变的数据(即仅输入)时,您只需查看函数原型即可知道. (3认同)

Dou*_* T. 123

这是一段带有常见错误的代码,const正确性可以保护您免受:

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

  • 当然,大多数现代编译器警告条件中的赋值,我们都将处理警告打开为错误标志,右: - > (35认同)
  • 所以我们说const是必要的,因为一些血腥的白痴选择"="作为C中的赋值运算符?;-) (17认同)
  • 在这个例子上不要太难:这是一些开发人员传福音的相同例子,说服我们使用if(0 == i)而不是if(i == 0).最后,Doug的代码模式可以在"if"语句之外使用.重要的是它以幽默的方式展示了const的一个好处.+ 1. (7认同)
  • @Roger你认为我们生活在一个建筑干净,无需警告的世界里.我的经验是,在很多代码中警告会在噪音中丢失.此外,还有很多代码在if表达式中进行赋值,许多代码认为它是一种有效的"好"风格. (7认同)
  • 一些编译器(和棉绒)已经对此发出警告很长时间了,与const相比,捕获这种错字比使用const更有用:http://codepad.org/Nnf5JUXV。 (2认同)
  • @Doug:这不是关于样式的,因为我自己使用这个模式:你可以用`if((a = b))`来表达它,这也使它更具可读性.我不会在这里打开关于编译器警告的争论,但我会指出各种lint工具更易配置(所以没有噪音),不要求你改变你的编译器,并且完全解决了==的问题/ = typos,而使用const只捕获其中一些. (2认同)
  • 这不能解决问题。在这里抛出错误仅仅是常量性的副作用。当变量需要可变时,它不会为您省钱。与(1 == x)模式相同;当您需要比较2个标识符时,它不会节省您的时间。唯一的解决方案是1:充分理解语言,以至于您不会在这个愚蠢的地方犯错(不难。在用C语言编程的12年中,我从未见过此bug);2:使用编译器将其标记为错误,并要求您将分配内容括在括号中;或3:在DEFCON上设置观察点并使用调试器 (2认同)

Chr*_*yer 60

似乎每次我将某些东西标记为const时,我都会收到错误,并且必须将某些其他函数更改为const.然后这导致我必须在其他地方更改另一个功能.这是通过经验变得更容易吗?

从经验来看,这是一个完整的神话.当非const-correct与const-correct代码坐在一起时,肯定会发生这种情况.如果你从一开始就设计const-correct,那绝不应该是一个问题.如果你做了一些const,然后别的东西不能编译,编译器告诉你一些非常重要的东西,你应该花时间正确地修复它.

  • 很少有人总是从干净的代码库开始.大多数编码都是遗留代码的维护,引用的注释非常准确.我在编写新的叶子函数时使用const,但我怀疑是否值得通过半打或十几个不熟悉的代码调用级别来追逐事物. (7认同)
  • 这有助于我防止这么多错误,我有一个const函数即将调用非const函数,因为我忘了它修改下面的数据. (6认同)
  • 根据我的经验,这是完全错误的。嵌套点类型使这类事情最头疼,在单个类型中可以有多个const量词。 (2认同)
  • “如果从一开始就设计const-correct,”实际上您有多少次从一开始就强制执行const-correctness?我们大多数人每天都必须处理大量的API和库,但事实并非如此,您几乎无能为力。因此,我同意OP的观点“似乎每次将某物标记为const时我都会得到一个错误a”。 (2认同)

Ant*_*ley 30

在您最初编写代码时,它不适合您.这是为了其他人(或几个月之后),他们正在查看类或接口中的方法声明以查看它的作用.不修改对象是从中收集的重要信息.

  • 将const-correctness放入的最佳时机是最初编写API时.否则,当你进行改造时,你会遇到const-poisoning的问题(这就是为什么将它添加到旧代码是*在新代码中执行它的完全不同的事情). (5认同)
  • 究竟.最好有"const int Value = 5;" 而不是"int ConstValue = 5;".+1. (2认同)

QBz*_*ziZ 25

如果你严格使用const,你会惊讶于大多数函数中的实数变量很少.通常只不过是一个循环计数器.如果你的代码达到了这一点,你会感觉内心温暖......通过编译验证......函数式编程的领域就在附近......你现在几乎可以触摸它...

  • 由于 C++17 和 constexpr 优点,我正在编写编译时单元测试......越来越接近...... (2认同)
  • 目前,由于范围的原因,我什至消除了循环计数器。 (2认同)

Joh*_*McG 21

const是您作为开发人员所做的一项承诺,并且在编写程序帮助时强制执行.

我的正确理由:

  • 它与您的函数的客户端通信,您不会更改变量或对象
  • 通过const引用接受参数可以获得通过引用传递的效率以及传递值的安全性.
  • 将接口编写为const正确将使客户端能够使用它们.如果您编写接口以接受非const引用,那么使用const的客户端将需要抛出constness以便与您合作.如果您的接口接受非const char*,并且您的客户端使用std :: strings,那么这尤其令人讨厌,因为您只能从它们获取const char*.
  • 使用const将使编译器保持诚实,这样你就不会错误地改变那些不应该改变的东西.


Pat*_*otz 19

我的理念是,如果你打算使用一种挑剔的语言进行编译时检查,那么就可以充分利用它. const是一种编译器强制执行的方式来表达你的意思 ......它比评论或doxygen更好.你付出了代价,为什么不拿出价值呢?


and*_*ykx 19

没有const的C++编程就像没有安全带的驾驶一样.

每次踏入汽车时都要戴上安全带,而365天中的安全带会安全到达.

唯一的区别是当你遇到汽车问题时你会立刻感受到它,而对于没有const的编程,你可能需要搜索导致该崩溃的两周时间才发现你无意中搞砸了一个函数参数你通过非const引用来提高效率.


bk1*_*k1e 16

对于嵌入式编程,const在声明全局数据结构时明智地使用可以通过使常量数据位于ROM或闪存中而无需在引导时复制到RAM来节省大量RAM.

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

在大型项目上与其他程序员合作时,const正确使用有助于防止其他程序员限制您.


Chr*_*ung 12

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;
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*acs 12

const正确性是从一开始就真正需要的东西之一.正如您所发现的,稍后添加它会非常困难,特别是当您添加的新函数与已存在的旧非常量函数之间存在很多依赖关系时.

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

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };
Run Code Online (Sandbox Code Playgroud)

如果我们没有const-correctness,那么你将不得不求助于按值返回复杂对象,以确保没有人在你背后操纵B级的内部状态.

简而言之,const-correctness是一种防御性编程机制,可以帮助您避免痛苦.


Gre*_*ers 6

假设你在Python中有一个变量.你知道你不应该修改它.如果你不小心怎么办?

C++为您提供了一种方法来保护自己不会意外地做一些您本来不应该做的事情.从技术上讲,无论如何你都可以绕过它,但是你必须投入额外的工作来拍摄自己.


Óla*_*age 5

这里有一篇关于 c++ 中 const 的好文章。这是一个非常直接的意见,但希望对一些人有所帮助。