我经常陷入困境,是否应该让一个成员方法常量或没有的情况下,这两个选项都工作得很好,并产生完全相同的结果。
考虑以下两个示例类:
class A
{
public:
/* Valid const correctness */
int get() const { return x; };
private:
int x = 0;
};
class B
{
public:
/* Questionable const correctness */
int* get() const { return x; };
private:
int* x = nullptr;
};
int main()
{
B b;
int* x = b.get();
// This defeats the purpose of const keyword
x = new int(1);
}
类A
是const正确性的一个很好的例子;但是,B
类是有问题的:get()
成员函数是否应该标记为const是有疑问的。const
应该暗示子对象不会被修改,如果函数修改其成员,则会导致编译时错误。
在第一个例子中,函数不修改它的成员,调用者也不能修改它;然而,在第二个例子中,调用者可以修改指针,这使得const关键字有问题。
我努力尽可能地使const正确,但在这些情况下我不确定,所以我的问题是,什么才是好的代码设计?如果返回一个调用者可以修改的引用或指针,是否放置const关键字?
3条答案
按热度按时间hgqdbh6s1#
你的问题是关于“返回一个指针或引用”和
const
-成员函数的正确性。但是对于指针(由copy 1返回)和引用的情况是非常不同的。通过引用返回的getter的无效
const
正确性问题是一个重要问题。下面的代码有'proper'
const
-correctness,无论我们将T
作为int
还是int*
:然而,当返回一个 reference 到一个数据成员时,该数据成员在任何返回它的函数中都被认为是
const
(除非它被声明为mutable
),所以下面的代码将无法编译:这将生成如下代码行沿着编译器错误(来自clang-cl):
错误:将类型'T'(aka 'int')的引用绑定到类型'const T'(aka 'const int')的值会删除'const'限定符
在后一种情况下,我们必须还将
const
限定符添加到返回类型中:此外,返回的
const
引用不能分配给非常量引用,因此使用这些const
限定符将阻止调用者修改私有数据成员:(Note你也可以在我展示的第一个代码片段中添加前导
const
限定符-但这是多余的,因为get()
表达式永远都是右值,无论如何都不能直接修改。1这里,我讨论的是一个本身就是指针的数据成员(并且通过复制返回)。然而,在getter返回数据成员的地址的情况下,上面关于引用类型的讨论以非常相似的方式应用,并且下面的代码在所需的
const
-correctness方面是“等效的”:xlpyo6sf2#
只要有可能,就创建方法
const
。在你的例子中,这是可能的,因为const
方法创建了const B* this
,因此int* const x
。你不能将x
改为指向另一个int
,但可以返回int*
。p8ekf7hl3#
DR,这取决于。
对于指针,有两个独立的常量概念。
智能指针也是如此,例如
const unique_ptr<int>
和unique_ptr<const int>
。原则上可以创建一个“深度常量”智能指针,其中指针本身的常量意味着指向对象的常量,但这样的智能指针很少有用。它们在标准库中找不到。
另一方面,容器通常具有深度恒定性。
所以你应该问问自己:我的类是更像指针还是更像容器?
如果它更像一个指针,那么一个
get() const
返回一个非常量指针是可以的。如果它更像一个容器,那么有两个重载的
get()
:关于引用的同样的推理也是有效的。没有智能引用,但是有引用 Package 器,它们或多或少地充当指针。