[英]const and non-const versions of *static* member functions
我有两个版本的相同的静态成员函数:一个采用指向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
};
(我知道玩指针通常是一个坏主意,但我正在实现一个数据结构。)
我在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));
}
在第一种方法中,代码在一个带有指针到const参数的函数中。
在第二种方法中,代码在一个函数中,该函数接受指向非const的参数。
通常应该使用哪种方法? 两个都正确吗?
最重要的规则是接口函数(公共方法,详细命名空间中的一个以外的自由函数等)不应抛弃其输入的常量。 Scott Meyer是第一个谈论使用const_cast防止重复的人之一,这是一个典型的例子( 如何删除类似的const和非const成员函数之间的代码重复? ):
struct C {
const char & get() const {
return c;
}
char & get() {
return const_cast<char &>(static_cast<const C &>(*this).get());
}
char c;
};
这是指实例方法而不是静态/自由函数,但原理是相同的。 您注意到非const版本添加了const来调用另一个方法(对于实例方法, this
指针是输入)。 然后它最后抛弃了constness; 这是安全的,因为它知道原始输入不是const。
反过来实现这一点非常危险。 如果你抛弃了你收到的函数参数的constness,如果传递给你的对象实际上是const,你在UB中冒了很大的风险。 也就是说,如果你调用任何实际改变对象的方法(现在你已经抛弃const就很容易做到),你可以轻松获得UB:
C ++标准,第5.2.11 / 7节[const cast]
[注意:根据对象的类型,通过指针,左值或指向数据成员的指针的写入操作会导致const-qualifier的const_cast,这可能会产生未定义的行为。 - 尾注]
它在私有方法/实现函数中并没有那么糟糕,因为你可能会仔细控制它被调用的方式/时间,但为什么这样做呢? 没有任何好处更危险。
从概念上讲,通常情况下,当你有一个相同函数的const和非const版本时,你只是传递对象的内部引用( vector::operator[]
是一个规范的例子),而不是实际上是在改变任何东西,这意味着你写它的方式都是安全的。 但抛弃输入的常量仍然更危险; 虽然你可能不太可能弄乱自己,想象一个团队设置,你用错误的方式写它并且工作正常,然后有人改变实现以改变某些东西,给你UB。
总之,在许多情况下,它可能没有实际的区别,但是有一种正确的方法可以做到这一点,它比替代方案更好: 将 constness 添加到输入中 ,并从输出中 删除 constness。
我以前只见过你的第一个版本,所以根据我的经验,这是更常见的习语。
第一个版本对我来说似乎是正确的,而第二个版本可能会导致未定义的行为,如果(A)您将实际的const对象传递给函数和(B) long code
写入该对象。 鉴于在第一种情况下,编译器将告诉您,如果您尝试写入对象,我将永远不会推荐选项2。 您可以考虑使用/返回const的独立函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.