m0m*_*eni 50 c++ refactoring const
经过大量的谷歌搜索后,我发现了很多关于标记函数及其参数的内容const,但没有关于标记变量的指南const.
这是一个非常简单的例子:
#include <string>
#include <iostream>
void example(const std::string& x) {
size_t length = x.length();
for (size_t i = 0; i < length; ++i) {
std::cout << x.at(i) << std::endl;
}
}
int main() {
example("hello");
}
Run Code Online (Sandbox Code Playgroud)
为什么不做
size_t length = x.length();
Run Code Online (Sandbox Code Playgroud)
const喜欢
const size_t length = x.length();
Run Code Online (Sandbox Code Playgroud)
按照惯例?
我知道这么小的一个简单的例子确实没有给这个带来任何巨大的好处,但它似乎对于一个更大的代码库有帮助,你可能会意外地改变你不应该变异的变量.
尽管有这样的好处,但我并没有真正看到它使用那么多(在我见过的C++代码库中)或者提到的几乎和函数及其参数一样多const.
除了必须输入5个额外字符外,还有一些缺点吗?我在这个话题上找不到太多东西,如果这是一个有这么多争议的问题,我不想在脚下射击.
Jes*_*uhl 40
标记您不修改的变量没有缺点const.
有一些上双方虽然:编译器会帮你诊断,当你无意中修改你不应该/不意味着一个变量,编译器可能(尽管由于具有语言const_cast和mutable这是罕见的)生成更好的代码.
所以,我建议; 使用const您可以在其中.没有缺点,您的编译器可以帮助您发现错误.没有理由不(除了一点额外打字).
请注意,这也扩展到成员函数.尽可能制作它们const- 它可以让它们在更多的上下文中使用,并帮助用户推理代码("调用此函数不会修改对象"是有价值的信息).
Mat*_* M. 19
我至少可以想到两个缺点:
const两者都值得.
冗长是一种经常听到的反对显性的论据,但是人们常常会以理解速度来误读速度.在冗长和显性之间存在平衡,当然,过于冗长可能会淹没有用信息,但过于隐含/简洁可能不会呈现必须重建/推断/推断/的信息.
就个人而言,我使用强类型静态检查语言,以便编译器尽早发现我的错误; 注释const用于向读者和编译器提供信息.我认为值得额外的6个符号.
至于惯性,删除const可能只是改变的一小部分......它通过强迫你经历所有使用它的地方来回报自己并查看周围的代码以确保它实际上可以删除它const.突然修改先前不可变的代码路径中的特定数据片段需要确保代码路径(或其调用者)的任何部分都不会意外地依赖于这种不变性.
而不是这个非标准代码:
#import <string>
#import <iostream>
void example(const std::string& x) {
size_t length = x.length();
for (size_t i = 0; i < length; ++i) {
std::cout << x.at(i) << std::endl;
}
}
int main() {
example("hello");
}
Run Code Online (Sandbox Code Playgroud)
......我写这个:
#include <string>
#include <iostream>
using namespace std;
void example( string const& s )
{
for( char const ch : s )
{
cout << ch << '\n';
}
}
auto main()
-> int
{ example( "hello" ); }
Run Code Online (Sandbox Code Playgroud)
const相对于原始代码,我可以添加的主要位置ch是循环中的变量.我觉得这很好.const通常是可取的,因为它减少了必须考虑的可能的代码操作,并且基于范围的循环可以让您拥有更多const.
使用const大多数东西的主要缺点是,当你必须与C API相关时.
然后,只需要做出一些直觉决定是否复制数据,或信任文档并使用const_cast.
附录1:
请注意,const返回类型会阻止移动语义.据我所知,Andrei Alexandrescu在Dobbs Journal博士的Mojo(C++ 03移动语义学)文章中首次提到这一点:
" [A]
const临时看起来像矛盾,这是一个矛盾.从实际角度来看,const临时人员强迫目的地复制.
所以,这是一个不应该使用的地方const.
对不起,我原本忘了提这个; 用户bogdan对另一个答案的评论提醒我.
附录2:
在同样(支持移动语义),如果有一个正式的说法做的最后一件事是不是在一些地方保存副本,然后通过引用传递给const它可以更好地使用非const按值传递参数,因为它可以简单地从.
即,而不是
string stored_value;
void foo( string const& s )
{
some_action( s );
stored_value = s;
}
Run Code Online (Sandbox Code Playgroud)
......或优化的冗余
string stored_value;
void foo( string const& s )
{
some_action( s );
stored_value = s;
}
void foo( string&& s )
{
some_action( s );
stored_value = move( s );
}
Run Code Online (Sandbox Code Playgroud)
......考虑一下写作
string stored_value;
void foo( string s )
{
some_action( s );
stored_value = move( s );
}
Run Code Online (Sandbox Code Playgroud)
它可以是左值实际参数的情况下稍微低效率的,它丢弃的优势const(上什么该代码可能会做的约束),并且它打破了使用统一的约定const只要有可能,但它并没有任何表现不佳情况(这是主要目标,以避免这种情况),它是更小,可能更清晰的代码.
注意:
¹标准C++没有#import指令.此外,如果正确包含这些标头,则无法保证size_t在全局命名空间中定义这些标头.
对于size_t length像这样的简短方法中的局部变量,它并不重要.额外冗长的缺点基本上与避免错别字意外修改长度的相对安全性相平衡.做任何你当地的风格指南,或你自己的直觉告诉你.
对于更长或更复杂的方法,它可能会有所不同.但话又说回来,如果你有一个如此复杂的方法,那么你可能至少应该考虑将代码重构为更简单的部分......无论如何,如果你阅读并理解代码,那么显式提供的额外提示const有点无关紧要 - 很好但无关紧要.
稍微相关,虽然您没有问过它:对于您的example方法的参考参数,您肯定需要const,因为您可能需要传递一个const字符串.只有当你想要禁用传递const字符串时(因为你认为你将添加代码来修改它),你应该省略const它.
| 归档时间: |
|
| 查看次数: |
1957 次 |
| 最近记录: |