现代c++中的内联方法和代码可读性

inline methods and code readability in modern C++

本文关键字:方法 代码 可读性 c++ 现代      更新时间:2023-10-16

好吧,有时候我的"编码大脑"会跳过一个档位;偶尔你能听到齿轮的摩擦声。(例如,每隔一段时间我就会写class Foo : Bar {},然后提醒自己这已经不合适了——而且已经很长时间了)。

我目前的习惯是在不牺牲速度的情况下使用内联方法来提高代码的可读性和可维护性,但是我最近遇到了一个问题,这使我对这种做法产生了质疑。

因此,给定(无可否认是人为的)代码,如:
double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Magic Formula. This does what?
a = b + c - (b * c); 
...

我会写:

double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Oh! It's probability!
a = ProbabilisticOr(b, c);
...
inline double ProbabilisticOr(double b, double c)
{
   // Skip the Sanity checks
   return b + c - (b * c);
}

我现在正在研究的数学相当复杂。如果我想要一个通用的CS/CE能够维护它,它必须写得更像第二个。这段代码对时间也很敏感。

我最近遇到了一个问题,正如我上面所说的。我像一个优秀的小程序员一样写数学常数static const double ...;但是当试图内联访问它们时,编译器会为dll而爆炸。目标操作系统是Linux,但我是在Windows (Visual Studio 2013)上开发的,并希望保持它"跨平台安全"。

解决这个小问题的办法是让他们脱离现实;但是,这会影响我的表现吗?考虑到涉及深奥的数学,可读性是一个严肃的问题;但它仍然必须表现良好。

更新:

澄清一下,使用更多/不同的——和更做作的——代码:

#ifndef BUILD_DLL
#  define DLL_MODE __declspec(dllimport)
#else
#  define DLL_MODE __declspec(dllexport)
#endif

class DLL_MODE ContrivedProbabilityExample
{
public:
   inline ContrivedProbabilityExample(double value);
   inline ContrivedProbabilityExample& operator+=(double value);
private:
   inline void CheckValue(double value);
private:
   static const double ZERO_PROB = 0.0;
   static const double GUARANTEED_PROB= 1.0;
   double probability;
private:
   // Not implemented
   ContrivedProbabilityExample();
};
inline ContrivedProbabilityExample::ContrivedProbabilityExample(double value) : probability(value) 
{
   CheckValue(value);
}
inline ContrivedProbabilityExample& ContrivedProbabilityExample::operator+=(double value)
{
   CheckValue(value);
   probability = probability + value - (probability * value);
}
inline void ContrivedProbabilityExample::CheckValue(double value)
{
   if(value < ZERO_PROB || value > GUARANTEED_PROB) 
      throw std::range_error("Hey, whattaya think you're doing?");
}

这段代码在两个平台的Static中都可以正常工作;它将在Linux上作为共享库工作。当尝试将其用作DLL时,它将在Windows下给出错误。唯一的解决方法是将CheckValue方法移出。

"老派"inlineCheckValue方法的代码"按原样"替换为调用它的地方;显然,"新派"内联确实……没有什么?(因为编译器显然不顾一切地做它想做的事。)

AFIK使此工作在DLL下的唯一方法是将CheckValue移出行…对于时间敏感的"老派"代码(每次调用都是/被保证的函数开销)来说,这可能是一个问题。这仍然是个问题吗?是否有"更好"的方法来保持可读性;例如,不要假设为我编写代码的每个CS/CE都精通统计学?

注意:这是跨平台的,所以"编译器"可能不是一个有意义的短语。

您想使用constexp,例如:

inline constexpr double ProbabilisticOr(double b, double c)
{
    // Skip the Sanity checks
    return b + c - (b * c);
}

那么你可以自由地做如下事情:

static const double a = ProbabilisticOr(b, c);

如果您的问题是确保性能,最好的处理方法是插入一个assert()来执行完整性检查。

应该由调用者来确保正确的值传递给你的概率函数(并且应该有很好的文档记录),如果一些调用者不这样做,assert()将帮助你调试。然而,当您发布代码时,您可以简单地停用所有断言,从而消除检查的性能损失。

没有什么比根本不检查更快的了,这就是为什么C/c++中的解引用指针从来都不是安全的,也永远不会是安全的。

不知道你的问题是什么,但是这个呢:

class DLL_MODE ContrivedProbabilityExample
{
public:
   ContrivedProbabilityExample(double value)
   { CheckValue(value); }
   ContrivedProbabilityExample& operator+=(double value)
   {
       CheckValue(value);
       probability = probability + value - (probability * value);
   }
private:
   void CheckValue(double value)
   {
       if(value < ZERO_PROB || value > GUARANTEED_PROB) 
           throw std::range_error("Hey, whattaya think you're doing?");
   }
private:
   constexpr double ZERO_PROB = 0.0;
   constexpr double GUARANTEED_PROB= 1.0;
   double probability;
private:
   // Not implemented
   ContrivedProbabilityExample();
};