我有两个版本的相同的静态成员函数:一个采用指向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的参数.
通常应该使用哪种方法?两个都正确吗?
最重要的规则是接口函数(公共方法、除详细命名空间中的函数之外的自由函数等)不应放弃其输入的常量性。Scott Meyer 是第一个谈论使用 const_cast 防止重复的人之一,这里有一个典型的例子(How do I remove code duplication between like const and non-const member functions?):
\n\nstruct 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;\nRun Code Online (Sandbox Code Playgroud)\n\n};
\n\n这是指实例方法而不是静态/自由函数,但原理是相同的。您注意到非常量版本添加了 const 来调用其他方法(对于实例方法,指针this是输入)。然后它在最后抛弃了常量;这是安全的,因为它知道原始输入不是 const。
以相反的方式实现这一点将是极其危险的。如果您放弃接收的函数参数的常量性,并且传递给您的对象实际上是常量,则在 UB 中您将面临很大的风险。也就是说,如果你调用任何实际改变对象的方法(既然你已经抛弃了常量,那么很容易意外地做到这一点),你可以很容易地得到 UB:
\n\n\n\n\nC++ 标准,\xc2\xa7 5.2.11/7 节 [const 强制转换]
\n\n[ 注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写入操作可能会产生未定义的行为。\xe2\x80\x94结束注]
\n
在私有方法/实现函数中,它并没有那么糟糕,因为也许您仔细控制了它的调用方式/时间,但为什么要这样做呢?这样做更危险,而且没有任何好处。
\n\n从概念上讲,通常的情况是,当您拥有同一函数的 const 和非 const 版本时,您只是传递对象的内部引用(vector::operator[]一个规范的示例),而实际上并没有改变任何内容,这意味着不管你用什么方式写它都是安全的。但抛弃输入的常量性仍然更危险;虽然你自己不太可能把它搞砸,但想象一下一个团队设置,你以错误的方式编写它,但它运行良好,然后有人改变实现来改变某些东西,给你 UB。
总之,在许多情况下,它可能不会产生实际差异,但有一种正确的方法可以做到这一点,它比替代方案更好:向输入添加常量,并从输出中删除常量。
\n| 归档时间: |
|
| 查看次数: |
611 次 |
| 最近记录: |