简体   繁体   English

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

[英]const and non-const versions of *static* member functions

I have two versions of the same static member function: one takes a pointer-to-const parameter and that takes a pointer-to-non-const parameter. 我有两个版本的相同的静态成员函数:一个采用指向const的指针参数,并采用指向非const的参数。 I want to avoid code duplication. 我想避免代码重复。
After reading some stack overflow questions (these were all about non-static member functions though) I came up with this: 在阅读了一些堆栈溢出问题(这些都是关于非静态成员函数的)之后我想出了这个:

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
};

(I know juggling with pointers is generally a bad idea, but I'm implementing a data structure.) (我知道玩指针通常是一个坏主意,但我正在实现一个数据结构。)

I found some code in libstdc++ that looks like this: 我在libstdc ++中发现了一些代码如下:
NOTE: these are not member functions 注意:这些不是成员函数

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));
}

In the first approach the code is in a function that takes a pointer-to-const parameter. 在第一种方法中,代码在一个带有指针到const参数的函数中。
In the second approach the code is in a function that takes a pointer-to-non-const parameter. 在第二种方法中,代码在一个函数中,该函数接受指向非const的参数。
Which approach should generally be used? 通常应该使用哪种方法? Are both correct? 两个都正确吗?

The most important rule is that an interface function (public method, a free function other than one in a detail namespace, etc), should not cast away the constness of its input. 最重要的规则是接口函数(公共方法,详细命名空间中的一个以外的自由函数等)不应抛弃其输入的常量。 Scott Meyer was one of the first to talk about preventing duplication using const_cast, here's a typical example ( How do I remove code duplication between similar const and non-const member functions? ): 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;

}; };

This refers to instance methods rather than static/free functions, but the principle is the same. 这是指实例方法而不是静态/自由函数,但原理是相同的。 You notice that the non-const version adds const to call the other method (for an instance method, the this pointer is the input). 您注意到非const版本添加了const来调用另一个方法(对于实例方法, this指针是输入)。 It then casts away constness at the end; 然后它最后抛弃了constness; this is safe because it knows the original input was not const. 这是安全的,因为它知道原始输入不是const。

Implementing this the other way around would be extremely dangerous. 反过来实现这一点非常危险。 If you cast away constness of a function parameter you receive, you are taking a big risk in UB if the object passed to you is actually const. 如果你抛弃你收到的函数参数的constness,如果传递给你的对象实际上是const,你在UB中冒了很大的风险。 Namely, if you call any methods that actually mutate the object (which is very easy to do by accident now that you've cast away constness), you can easily get UB: 也就是说,如果你调用任何实际改变对象的方法(现在你已经抛弃const就很容易做到),你可以轻松获得UB:

C++ standard, section § 5.2.11/7 [const cast] C ++标准,第5.2.11 / 7节[const cast]

[ Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier may produce undefined behavior. [注意:根据对象的类型,通过指针,左值或指向数据成员的指针的写入操作会导致const-qualifier的const_cast,这可能会产生未定义的行为。 —end note ] - 尾注]

It's not as bad in private methods/implementation functions because perhaps you carefully control how/when its called, but why do it this way? 它在私有方法/实现函数中并没有那么糟糕,因为你可能会仔细控制它被调用的方式/时间,但为什么这样做呢? It's more dangerous to no benefit. 没有任何好处更危险。

Conceptually, it's often the case that when you have a const and non-const version of the same function, you are just passing along internal references of the object ( vector::operator[] is a canonical example), and not actually mutating anything, which means that it will be safe either way you write it. 从概念上讲,通常情况下,当你有一个相同函数的const和非const版本时,你只是传递对象的内部引用( vector::operator[]是一个规范的例子),而不是实际上是在改变任何东西,这意味着你写它的方式都是安全的。 But it's still more dangerous to cast away the constness of the input; 但抛弃输入的常量仍然更危险; although you might be unlikely to mess it up yourself, imagine a team setting where you write it the wrong way around and it works fine, and then someone changes the implementation to mutate something, giving you UB. 虽然你可能不太可能弄乱自己,想象一个团队设置,你用错误的方式写它并且工作正常,然后有人改变实现以改变某些东西,给你UB。

In summary, in many cases it may not make a practical difference, but there is a correct way to do it that's strictly better than the alternative: add constness to the input , and remove constness from the output . 总之,在许多情况下,它可能没有实际的区别,但是有一种正确的方法可以做到这一点,它比替代方案更好: constness 添加输入中 ,并从输出中 删除 constness。

I have actually only ever seen your first version before, so from my experience it is the more common idiom. 我以前只见过你的第一个版本,所以根据我的经验,这是更常见的习语。

The first version seems correct to me while the second version can result in undefined behavior if (A) you pass an actual const object to the function and (B) the long code writes to that object. 第一个版本对我来说似乎是正确的,而第二个版本可能会导致未定义的行为,如果(A)您将实际的const对象传递给函数和(B) long code写入该对象。 Given that in the first case the compiler will tell you if you're trying to write to the object I would never recommend option 2 as it is. 鉴于在第一种情况下,编译器将告诉您,如果您尝试写入对象,我将永远不会推荐选项2。 You could consider a standalone function that takes/returns const however. 您可以考虑使用/返回const的独立函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM