如书 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
提前致谢!
答案 0 :(得分:4)
如果您发现普通类型安全有助于您获得正确的系统(它 做;特别是在大型系统中),你会发现 const 正确性 也有帮助。
如果您不想意外或故意更改变量,则应使用const
。一些常量(全局变量和类静态,字符串和整数,但不是具有非平凡构造函数的变量)可以放在可执行文件的只读部分中,因此如果您尝试写入它就会导致分段错误。
你应该明确地使用const
作为遵循这个原则的函数的说明符以及函数参数。如果您不必更改实际参数,请将其设为const
。这并不限制此类函数的可能用途,而是扩展它们,因为现在它们可能用于const
个参数和const
个对象。
在声明中
const int* foo(const int* const&) const;
每个const
表示不同的内容,是的,显然应该使用,如果需要。
使用const
可提高程序的类型安全性。
[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 ++”中的怪异语句。