以const正确性卖给我

时间:2020-03-06 14:45:25  来源:igfitidea点击:

那么,为什么总是建议总是尽可能多地使用const呢?在我看来,在C ++中使用const可能比提供帮助更痛苦。但是再说一次,我是从python角度来的:如果我们不希望更改某些内容,请不要更改它。如此说来,这里有几个问题:

  • 似乎每次将某物标记为const时,我都会遇到错误,并且还必须在某个地方更改某些其他函数以使其成为const。然后,这使我不得不在其他地方更改另一个功能。有了经验,这会变得更容易吗?
  • 使用const的好处真的足以弥补麻烦吗?如果我们不打算更改对象,为什么不不编写不更改对象的代码呢?

我应该注意,在这一点上,我最关注的是将const用于正确性和可维护性的好处,尽管对性能的影响也很了解。

解决方案

这是一段具有常见错误的代码,使用const正确性可以防止出现以下情况:

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是一个好习惯,因为...

  • 它可以保护我们避免意外更改不希望更改的变量,
  • 它可以防止我们意外分配变量,并且
  • 编译器可以对其进行优化。例如,我们受到保护
if( x = y ) // whoops, meant if( x == y )

同时,编译器可以生成更有效的代码,因为它确切地知道变量/函数始终处于什么状态。如果我们正在编写紧凑的C ++代码,那很好。

我们是正确的,因为很难始终如一地使用const-correctness,但是最终代码更简洁,编程更安全。当我们进行大量C ++开发时,这种好处很快就会显现出来。

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正确性。每次我在实践中尝试严格地应用它时,它最终都会崩溃,并且const_cast开始使代码变得丑陋。

也许这只是我使用的设计模式,但是const总是会变得过于宽泛。

例如,假设有一个简单的数据库引擎...它具有架构对象,表,字段等。用户可能具有'const Table'指针,这意味着不允许他们修改表架构本身...但是如何操作与表关联的数据?如果Insert()方法标记为const,则必须在内部将const-ness抛弃以实际操作数据库。如果未标记为const,则它无法防止调用AddField方法。

也许答案是根据稳定性要求来划分类,但这会使设计变得更加复杂,其带来的好处超出了我的期望。

当我们使用" const"关键字时,我们将为类指定另一个接口。有一个包含所有方法的接口,以及一个仅包含const方法的接口。显然,这使我们可以限制对某些我们不想更改的内容的访问。

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

It seems like every time I mark
  something as const, I get an error and
  have to change some other function
  somewhere to be const too. Then this
  causes me to have to change another
  function somewhere else. Is this
  something that just gets easier with
  experience?

从经验来看,这是一个完全的神话。当然,当非const正确的代码与const正确的代码一起使用时,会发生这种情况。如果我们从一开始就设计const-correct,那么这绝对不是问题。如果我们使const,然后其他不符合要求,则编译器会告诉我们一些非常重要的信息,我们应该花些时间正确地修复它。

我的理念是,如果要在编译时检查中使用精挑细选的语言,而不是充分利用它,则可以。 const是一种编译器强制的方式来表达意思……比注释或者doxygen永远更好。我们要付出代价,为什么不获取价值呢?

const是我们作为开发人员所做的承诺,并在执行中争取了编译器的帮助。

我的const正确原因是:

  • 它与函数的客户端通信,我们将不会更改变量或者对象
  • 通过const reference接受参数使我们可以高效地进行引用传递,并可以安全地传递值。
  • 以正确的const格式编写接口将使客户端可以使用它们。如果编写接口以接受非const引用,则使用const的客户端将需要放弃constness以便与我们一起工作。如果接口接受非const char *,并且客户端使用的是std :: strings,这会特别令人讨厌,因为我们只能从它们中获取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...
}

没有const的C ++编程就像没有系安全带的情况下开车一样。

每次上车时都要系上安全带,这很痛苦,在365天中有364天可以安全到达。

唯一的区别是,当我们遇到汽车故障时,我们会立即感觉到它,而在没有const的编程下,我们可能必须搜索两周导致崩溃的原因,才发现我们无意中弄乱了一个函数参数,我们通过非常数参考传递的效率。

如果严格使用const,我们会惊讶的是,大多数函数中真正的变量很少。通常只不过是一个循环计数器。如果代码达到了这一点,我们会在内部产生温暖的感觉...通过编译进行验证...功能编程领域就在附近...我们现在几乎可以触摸它了...

const正确性是从一开始就真正需要采取的措施之一。正如我们所发现的,以后添加它是一个很大的痛苦,尤其是当我们要添加的新函数与已经存在的旧的非const正确函数之间存在很大的依赖性时。

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

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

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

简而言之,const-correctness是一种防御性编程机制,可以使我们免于日后的痛苦。