*static*成员函数的const和非const版本

Xac*_*ack 7 c++ const

我有两个版本的相同的静态成员函数:一个采用指向const的指针参数,并采用指向非const的参数.我想避免代码重复.
在阅读了一些堆栈溢出问题(这些都是关于非静态成员函数的)之后我想出了这个:

class C {
private:
  static const type* func(const type* x) {
    //long code
  }

  static type* func(type* x) {
      return const_cast<type*>(func(static_cast<const type*>(x)));
  }
public:
  //some code that uses these functions
};
Run Code Online (Sandbox Code Playgroud)

(我知道玩指针通常是一个坏主意,但我正在实现一个数据结构.)

我在libstdc ++中发现了一些如下所示的代码:
注意:这些代码不是成员函数

static type* local_func(type* x)
{
  //long code
}

type* func(type* x)
{
  return local_func(x);
}

const type* func(const type* x)
{
  return local_func(const_cast<type*>(x));
}
Run Code Online (Sandbox Code Playgroud)

在第一种方法中,代码在一个带有指针到const参数的函数中.
在第二种方法中,代码在一个函数中,该函数接受指向非const的参数.
通常应该使用哪种方法?两个都正确吗?

Nir*_*man 2

最重要的规则是接口函数(公共方法、除详细命名空间中的函数之外的自由函数等)不应放弃其输入的常量性。Scott Meyer 是第一个谈论使用 const_cast 防止重复的人之一,这里有一个典型的例子(How do I remove code duplication between like const and non-const member functions?):

\n\n
struct C {\n  const char & get() const {\n    return c;\n  }\n  char & get() {\n    return const_cast<char &>(static_cast<const C &>(*this).get());\n  }\n  char c;\n
Run Code Online (Sandbox Code Playgroud)\n\n

};

\n\n

这是指实例方法而不是静态/自由函数,但原理是相同的。您注意到非常量版本添加了 const 来调用其他方法(对于实例方法,指针this是输入)。然后它在最后抛弃了常量;这是安全的,因为它知道原始输入不是 const。

\n\n

以相反的方式实现这一点将是极其危险的。如果您放弃接收的函数参数的常量性,并且传递给您的对象实际上是常量,则在 UB 中您将面临很大的风险。也就是说,如果你调用任何实际改变对象的方法(既然你已经抛弃了常量,那么很容易意外地做到这一点),你可以很容易地得到 UB:

\n\n
\n

C++ 标准,\xc2\xa7 5.2.11/7 节 [const 强制转换]

\n\n

[ 注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写入操作可能会产生未定义的行为。\xe2\x80\x94结束注]

\n
\n\n

在私有方法/实现函数中,它并没有那么糟糕,因为也许您仔细控制了它的调用方式/时间,但为什么要这样做呢?这样做更危险,而且没有任何好处。

\n\n

从概念上讲,通常的情况是,当您拥有同一函数的 const 和非 const 版本时,您只是传递对象的内部引用(vector::operator[]一个规范的示例),而实际上并没有改变任何内容,这意味着不管你用什么方式写它都是安全的。但抛弃输入的常量性仍然更危险;虽然你自己不太可能把它搞砸,但想象一下一个团队设置,你以错误的方式编写它,但它运行良好,然后有人改变实现来改变某些东西,给你 UB。

\n\n

总之,在许多情况下,它可能不会产生实际差异,但有一种正确的方法可以做到这一点,它比替代方案更好:向输入添加常量,并从输出中删除常量。

\n