【问题标题】:Why is it useful to make a const function?为什么创建一个 const 函数很有用?
【发布时间】:2010-12-24 03:56:59
【问题描述】:

如果你只能读取变量而不能写入(类变量),为什么将函数设为 const 如此有用?

【问题讨论】:

  • 可以写变量。你就是不能写类变量。
  • 我的意思是,但我忘了包括它。

标签: c++ winapi visual-c++ constants


【解决方案1】:

如果你向你的类的实例传递了一个 const 指针或 const 引用,那么它只能调用该类的 const 方法(如果有的话)。

显然,如果您从不关心您的类型的 const 正确性,那么您可以忽略这一点。

我想它也可以帮助编译器在某些情况下优化事物,尽管我对此表示怀疑,即使它确实有帮助,允许那个小的改进(如果有的话)来决定你如何编写你的代码将是一个为时过早的情况大多数情况下的优化。

【讨论】:

  • wrt 优化:编译器可以根据 const 的正确性进行积极的优化,特别是当方法体对翻译不可见时。它对编译器可能与限制关键字一样有用(它可以以 10 倍以上的速度生成代码,因为它不必加载和存储每个可能更改的地址)。 iow,如果您启用优化并遵循 const 正确性,编译器可能会将函数视为 const 并假设它基于对象数据持有的值没有改变,因此不需要重新读取。
  • 当软件挑战主要与正确性有关时,C++ 人似乎总是痴迷于性能,这让我感到很遗憾。
【解决方案2】:

这样您就不会“意外”修改类变量之一。这只是一种安全措施。

(如果您在确实修改类的任何数据成员的函数之后使用 const 关键字 - 直接或通过另一个函数调用 - 您将收到编译错误)。

【讨论】:

  • 请注意,这不是太多的安全措施;你总是可以通过投射来解决它。
  • @dan04:这是一种误解。仅在极少数情况下使用const_cast 修改对象是合法的,几乎只有在const_cast 的用户首先将const 修饰符添加到最初不是const 的指针或引用中.
【解决方案3】:

一个原因是const 是一种病毒。这意味着如果部分代码是 const 正确的,那么其余代码将无法与该部分互操作。

如果您忽略 const 正确性,您的类与其他库(从标准库开始)协同工作的可能性很小。

例如:

#include <vector>
#include <algorithm>

struct X
{
    int n;
    bool operator< (X b)
    { 
        return n < b.n;
    }
};

int main()
{
    std::vector<X> vec;
    std::sort(vec.begin(), vec.end());
}

使用 codepad.org

In function 'const _Tp& std::__median(const _Tp&, const _Tp&, const _Tp&) [with _Tp = X]':
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2642:   instantiated from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >, _Size = int]'
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2713:   instantiated from 'void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >]'
t.cpp:17:   instantiated from here
Line 90: error: no match for 'operator<' in '__a < __b'

与标准库兼容的比较运算符必须保证不会修改参数。如果对象在比较时确实发生了变化,那么尝试对它们进行排序将是徒劳的。

另一个例子:你不能通过 const 引用来传递参数,这是传递大对象的传统方式。相反,您必须通过可修改的引用传递参数。现在您将无法将任何类型的临时对象传递给您的函数。

【讨论】:

    【解决方案4】:

    如果你有一个 const 对象,它只允许 const 成员函数对其进行操作。

    【讨论】:

      【解决方案5】:

      调用者和被调用者之间的合同越多,您可以在代码而不是文档中表达,编译器就越能帮助您遵守该合同(从两端)。隐式this 指针的常量性是其中的重要部分,所有其他参数引用的常量性也是如此。 (当然,按值传递参数的顶级常量不是合同的一部分)

      【讨论】:

        【解决方案6】:

        好处是您可以让编译器强制执行可以修改状态的位置。例如,如果您使用私有数据创建一个类,并且它的所有方法(例如构造函数除外)都是 const,那么您就有一个不可变的数据类型。这样做的好处不是性能之一,而是语义之一。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-02-09
          • 2011-08-03
          • 1970-01-01
          • 2019-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多