在C ++中尽可能使用const?

时间:2014-03-09 17:53:39

标签: c++ pointers reference const keyword

如书 Effective C ++ :“尽可能使用const”中所述,人们会认为这个定义:Vec3f operator+(Vec3f &other);更好地定义为Vec3f operator+(const Vec3f &other) const;甚至更好为const Vec3f operator+(const Vec3f &other) const;

或者使用5个 const 关键字的示例:const int*const Foo(const int*const&)const;

当然,你应该只包含 const 。我问的是,尽可能使用它们是一种好习惯吗?虽然它确实为您提供了更多错误安全的代码,但它可能会变得非常混乱。或者,例如,你应该忽略指针和引用const(除非你真的需要它),并且只在类型本身上使用它,就像const int* Foo(const int* parameter)const;一样,所以它最终不会太乱了吗?

其他信息: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

提前致谢!

5 个答案:

答案 0 :(得分:4)

  

C++ FAQ

     

如果您发现普通类型安全有助于您获得正确的系统(它   做;特别是在大型系统中),你会发现 const 正确性   也有帮助。

如果您不想意外或故意更改变量,则应使用const。一些常量(全局变量和类静态,字符串和整数,但不是具有非平凡构造函数的变量)可以放在可执行文件的只读部分中,因此如果您尝试写入它就会导致分段错误。

你应该明确地使用const作为遵循这个原则的函数的说明符以及函数参数。如果您不必更改实际参数,请将其设为const。这并不限制此类函数的可能用途,而是扩展它们,因为现在它们可能用于const个参数和const个对象。

在声明中

const int* foo(const int* const&) const;

每个const表示不同的内容,是的,显然应该使用,如果需要

摘要

使用const可提高程序的类型安全性。

  

C++ FAQ

     

[18.3]我是否应该尝试将事情 const 更正,并且#34;更快"或者"以后"?

     

在非常非常非常开始的时候。

答案 1 :(得分:3)

尽可能使用const通常是一件好事,但这是一个糟糕的措辞。您应该尽可能使用const 并且有意义

最重要的是(它可能很少会打开额外的优化机会),这是一种记录你不修改内容的意图。

在您提供的成员operator+的具体示例中,最佳解决方案不是制作所有内容const,而是基于成员{{1}的独立operator+并按值获取一个参数:

operator+=

此解决方案适用于出现在加号两侧的T operator+(T one, T const& two) const { return one += two; } ,它允许链接,不会复制代码,并且它允许编译器执行最大程度的优化。
T的语义要求制作副本,因此您也可以让编译器进行复制(另一个将被优化)。

可以使operator+成为one,但是您必须手动制作副本,这可能是次优的(并且更不易于理解)。

答案 2 :(得分:1)

使用const时,你告诉编译器一些东西。

然后,它可以使用该信息来检查您是否正在做一些您不应该做的事情,并使其能够优化代码。

因此,当使用const时,它可以让它变得更聪明。

答案 3 :(得分:0)

我认为尽可能使用const是一个很好的方法。它为您的代码添加了隐式文档,并增加了类型安全性,如其他答案所述。

很高兴知道你可以调用const函数,而不必担心它们是否会改变对象的内部状态,并且传递const指针或对其他对象的引用将使其免于封装破损。它还允许拥有const引用的对象从引用所指向的内容中获得最大价值。

此外,从一开始就应用const是一个好主意,因为以后添加可能会很麻烦。例如,如果您有一个类:

class A
{
public:

  //...

  int getCount()
  {
    return m_count;
  }

private:
  int m_count;
}

另一个:

class B
{
public:

  //...

  int getInternalCount()
  {
    return m_a->getCount();
  }

private:
  A* m_a;
}

你想做的事:

void foo( const B* b )
{
  int count = b->getInternalCount();

  //-- Do something
}

这是一个非常有效的用例,但您必须将const添加到多个位置以支持它(B::getInternalCount()A::getCount())。如果你从一开始就这样做,它实际上很容易使用const,这使得设计对其他开发人员来说更加明显。如果你自己工作,它仍然有很大帮助,但它并不是一个问题。但是,当我在团队中工作时,我发现当我们开始执行const并改进我们的一些遗留代码以便更多地遵守它时,它确实有所帮助。

长话短说:我建议一直使用它。

答案 4 :(得分:0)

public abstract class BaseHostedService : BackgroundService { public MyConfigObject Config { get; set; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { ConfigureBaseClass(Config); DoWork(); } private void ConfigureBaseClass(MyConfigObject config) { // Use config to do something } public abstract void DoWork(); } public class CustomHostedService1 : BaseHostedService { private readonly ISomeService1 _someService; public CustomHostedService1(ISomeService1 someService) { _someService = someService; } public override void DoWork() { // Do some work here _someService.DoWork(); } } public class CustomHostedService2 : BaseHostedService { private readonly ISomeService2 _someService; private readonly ILogger<CustomHostedService2> _logger; public CustomHostedService2(ILogger<CustomHostedService2> logger, ISomeService2 someService) { _someService = someService; _logger = logger; } public override void DoWork() { // Do some work here _someService.DoWork(); } } 的最初目的是处理通常使用magic numbers和硬编码值时出现的问题。

有点愚蠢,但是风景如画的例子说明了这一点。这样的代码容易出错并且不方便。

const

您最好将Pi定义为常量。

c1 = 3.14159 * diameter1;
c2 = 3.14159 * diameter2;

与变量相比,常量具有“特权”。在您的示例中,通过const引用传递其他向量是有意义的,因为使用此函数,它将接受临时(rvalue)作为其参数。

const double PI = 3.14159;
c1 = PI * diameter1;
c2 = PI * diameter2;

借助Vec3f operator+(const Vec3f &other) const; // Would not be possible with Vec3f operator+(Vec3f &other) const; Vec3f v = u + Vec3f(1, 0, 0); ,您可以在诸如静态数组分配之类的上下文中使用常量

constexpr

因此,这并不是防止您不小心设置一些随机值(您必须是非常愚蠢的程序员才能犯此类错误)。只要有可能就使用它是没有意义的,而仅在您要指定常量时使用。

这不是我第一次看到“有效C ++”中的怪异语句。