C++ 常量应该传播到成员指针对象吗?

C++ 常量应该传播到成员指针对象吗?,c++,pointers,coding-style,constants,C++,Pointers,Coding Style,Constants,我有一个成员函数,声明为const,并通过指针修改数据。这似乎具有误导性。我应该删除const关键字吗 我想知道其他人如何在他们的代码中处理这种情况。人们只是添加一条评论来澄清正在发生的事情吗?他们没有将const关键字添加到成员函数中吗?也许完全是别的什么 感谢您的建议。一般来说,是的。修改您声明为常量的内容是一种欺骗,即使您可以这样做 如果有人使用您的代码并看到const,他们希望看到const。修改,即使对您来说是明智的,也可能会给他们带来严重的问题,甚至使程序崩溃。一般来说,是的。修改您

我有一个成员函数,声明为const,并通过指针修改数据。这似乎具有误导性。我应该删除const关键字吗

我想知道其他人如何在他们的代码中处理这种情况。人们只是添加一条评论来澄清正在发生的事情吗?他们没有将const关键字添加到成员函数中吗?也许完全是别的什么


感谢您的建议。

一般来说,是的。修改您声明为常量的内容是一种欺骗,即使您可以这样做


如果有人使用您的代码并看到const,他们希望看到const。修改,即使对您来说是明智的,也可能会给他们带来严重的问题,甚至使程序崩溃。

一般来说,是的。修改您声明为常量的内容是一种欺骗,即使您可以这样做


如果有人使用您的代码并看到const,他们希望看到const。修改,即使对您来说是明智的,也可能会给他们带来严重的问题,甚至使程序崩溃。

您基本上有两种选择:

深度常数:

浅常数:

这完全取决于你,也取决于你的课程目标。如果该类是一个智能指针,那么使用浅常量语义似乎是合理的,因为该类应该尽可能类似于原始指针,并且您当然可以使用指向非常量指针对象的常量原始指针


否则,您应该自问为什么要公开对成员指针对象的访问。当然,您可能希望通过对类的不断引用来提供可变访问,但我认为这是一种特殊而罕见的情况。首先,代码中不应该有那么多原始指针。通过取消引用指针来返回一个深度常量引用应该是可以的,但通常在封装得更好的getter函数中,它隐藏了类中存在指针的事实,比如T const&get const{return*ptr;}。

您基本上有两个选择:

深度常数:

浅常数:

这完全取决于你,也取决于你的课程目标。如果该类是一个智能指针,那么使用浅常量语义似乎是合理的,因为该类应该尽可能类似于原始指针,并且您当然可以使用指向非常量指针对象的常量原始指针

否则,您应该自问为什么要公开对成员指针对象的访问。当然,您可能希望通过对类的不断引用来提供可变访问,但我认为这是一种特殊而罕见的情况。首先,代码中不应该有那么多原始指针。通过取消引用指针来返回一个深度常量引用应该可以,但通常在封装得更好的getter函数中,它隐藏了类中存在指针的事实,比如T const&get const{return*ptr;}。

考虑std::vector成员与用于实现动态数组的Blah*成员。通常,用前者取代后者是有意义的。对于Blah*memeber,允许使用const方法修改数组中的数据,而对于std::vector成员,不允许使用const方法修改数组中的数据

还考虑一个具有索引方法的矩阵类,该方法返回一个允许对元素赋值的代理。通过代理进行赋值会更改矩阵,而不是代理对象本身。因此,代理对象的赋值操作符可以而且应该是常量,以便对其效果施加尽可能多的约束,而其主要任务是修改内容

这是设计层与编码层不同的另一个例子

在第一个示例中,对于成员数组,const是关于表示设计级别约束的,但在第二个示例中,对于赋值代理,const是关于表示编码级别约束的

然而,这些用法并非不兼容。关键思想是为代码读者提供尽可能多的约束,因为这大大减少了理解或处理代码时必须考虑的各种因素。结果:尽可能地添加常量。

考虑std::vector成员和用于实现动态数组的Blah*成员。通常,用前者取代后者是有意义的。对于Blah*memeber,允许使用const方法修改数组中的数据,而对于std::vector成员,不允许使用const方法修改数组中的数据

还考虑一个具有索引方法的矩阵类,该方法返回一个允许对元素赋值的代理。通过代理进行赋值会更改矩阵,而不是代理对象本身。因此,代理对象的赋值运算符可以而且应该是常量,以便对其效果施加尽可能多的约束,而其主要任务是修改 是的

这是设计层与编码层不同的另一个例子

在第一个示例中,对于成员数组,const是关于表示设计级别约束的,但在第二个示例中,对于赋值代理,const是关于表示编码级别约束的


然而,这些用法并非不兼容。关键思想是为代码读者提供尽可能多的约束,因为这大大减少了理解或处理代码时必须考虑的各种因素。结果:只要你能,就在任何地方添加常量。

你能发布一个sscce吗?看一个简单的例子怎么样?Mb函数应该是常量,类中的变量应该是可变的,Mb函数不应该是常量。想想函数的作用:它是否修改了用户认为属于对象的数据?如果答案是肯定的,那么它不应该是常量;如果答案是否定的,那么它应该是常量。你能发布一个sscce吗?看一个简单的例子怎么样?Mb函数应该是常量,类中的变量应该是可变的,Mb函数不应该是常量。想想函数的作用:它是否修改了用户认为属于对象的数据?如果答案是肯定的,那么它不应该是常量;如果答案是否定的,那么它应该是const。我大体上同意,但不同意如果有人使用您的代码并看到const,他们希望看到const。。可变的呢?如果我不能相信你的常量,我就不能相信你的代码。是的,如果它确实合适的话,你可以使用mutable,但一般来说它并不安全。我大体上同意,但不同意如果有人使用你的代码并看到const,他们希望看到const。。可变的呢?如果我不能相信你的常量,我就不能相信你的代码。是的,如果实际合适的话,您可以使用mutable,但一般来说它并不安全。请注意,deep constness实现仍然有一个漏洞,即您在const Foo上使用复制构造函数来获取具有相同存储指针的Foo,然后使用mutable接口,因为它不再是const。@EdwardZ.Yang:是的,是的,这个例子太简单了。您的deep const类型不应具有隐式副本。请注意,deep constness实现仍然存在漏洞,即您在const Foo上使用副本构造函数来获取具有相同存储指针的Foo,然后使用可变接口,因为它不再是const。@EdwardZ.Yang:是的,是的,该示例太椭圆了。深度常量类型不应具有隐式副本。
class Foo
{
    T * ptr;
public:
    T       & operator*()       { return *ptr; }
    T const & operator*() const { return *ptr; }
    T       * operator->()       { return ptr; }
    T const * operator->() const { return ptr; }
};
class Foo
{
    T * ptr;
public:
    T & operator*() const { return *ptr; }
    T * operator->() const { return ptr; }
};