我认为“const-correctness”的概念定义得非常明确,但当我与其他人谈论它时,似乎我们对它的含义有不同的看法。有人说它是关于在尽可能多的地方有“const”注释的程序。其他人将程序定义为const-correct,当且仅当使用const注释时没有违反constness(即,它是编译器为您检查的属性)。
所以我想知道,这些函数中哪些是正确的:
struct Person {
string getName1() const { return _name; }
string getName2() { return _name; }
string getName3() const { _name = "John"; return _name; }
string getName4() { _name = "John"; return _name; }
string _name;
};
我在互联网上搜索了定义,但实际上找不到明确的答案,我也怀疑可能有citogenesis的情况在起作用。那么,任何人都可以为定义提供任何可靠的引用吗?
答案 0 :(得分:6)
在我看来,“const correctness”意味着:
任何不打算修改的内容都应标记为
const
。
这意味着编译器可以告诉您何时出错。 (它也可能对某些条件下的优化产生影响,但这更多的是次要的好处,并取决于许多其他因素)
有三个基本的地方有用:
会员功能可以标记为const
,如您的示例所示。这意味着您从该函数中访问成员变量就好像变量本身是const
一样。 (这是您展示的示例,但getName3()
不起作用)
“免费”变量,本地变量和成员变量本身也可以标记为const
- 一旦初始化,它们可能不会被更改。示例 - 局部变量:
int f(int i) {
const int square = i*i;
// do something here that uses, but doesn't change square
return square;
}
或自由变量:
extern const double PI; // set somewhere else but not changed.
或成员变量:
class foo {
const int state; // can't be changed once constructed
foo(int s) : state(i) {}
};
函数参数也可以标记为const
,定义仍然可以匹配非const声明:
void f(int i);
void f(const int i) {
// the fact that i is const is an implementation detail of f here
}
在某些情况下,需要注意const
引用的正确性:
void g(const std::string& s);
void f(std::string& s);
在这两个中,可以在更多地方使用:
g("hi"); // Fine
f("hi"); // Not fine - you can't bind a temporary to a reference
当然,如果您意味着更改s
,那么无论如何传递临时信息都没有意义。
答案 1 :(得分:4)
来自parashift的文字:
这意味着使用关键字const来防止const对象获取 突变。
答案 2 :(得分:1)
只有getName3
违反了 const-correctness,因为_name
在函数体中是常量(具体来说,它是const std::string &
),{{1} } 不是 std::string::operator=
。
const
设计很差,因为它需要一个可变的上下文,即使它没有执行任何突变,所以应该声明getName2
,否则会导致令人惊讶的限制,即你不能通过const
来调用它。
你也可以在混音中添加“volatile”和“rvalue”正确性,这在精神上是相似的。
通过非局部效应可以感受到正确性。典型示例是关系运算符(const Person &
和operator<
):如果您未将它们标记为operator==
,则许多标准算法和容器将无法与您的类一起使用,因为它们通常适用运算符到常量元素引用。从这个意义上说,不是“尽可能的常量”会对代码的使用施加不必要的限制。从相反的观点来看,如果您自己的函数不必要地对对象进行 mutable 引用,则同样适用,因为这将阻止您不必要地使用常量引用并剥夺编译时检查操作您的操作思想是非变异的,实际上并没有改变对象。
答案 3 :(得分:0)
This faq chapter仅讨论c ++的const正确性。引用它:
这意味着使用关键字const来防止const对象获取 突变。
关于您的会员功能:
string getName1() const { return _name; }
这一个const-correct。它只返回成员变量的副本。
string getName2() { return _name; }
这个不是const-correct,因为它没有被声明为const成员。
string getName3() const { _name = "John"; return _name; }
不是const-correct,因为它修改了const成员函数中的成员变量。它应该产生编译错误。
string getName4() { _name = "John"; return _name; }
它是const-correct,因为它修改了一个成员变量。
答案 4 :(得分:0)
答案 5 :(得分:0)
getName3()不正确,因为它更改了名称。其他是正确的。
指定方法常量有时是有吸引力的,有时需要。当我完成项目的编码后,我会检查哪些方法可以保持不变,以提高我的代码的可读性。虽然仍在编码,但我没有指定方法很多,因为它阻碍了工作的进展。出于同样的原因,我宣布所有成员都公开,直到我完成编码,然后我适用私人和受保护。