关于c ++:处理非const-aware Library / SDK的最佳方法是什么?

What's the best way to deal with a non-const-aware Library/SDK?

我已经在3dsmax sdk上工作了更长时间,它几乎在所有部分都不使用const。因此,即使是BitmapWidth()Height()吸气剂也没有标记为const。在小项目中,这已经是一个真正的烦恼了,但自从我在一个更大的项目中工作以来,它变得越来越可怕。

例如,出于性能原因,我在多个类实例中持有单个Bitmap实例作为shared_ptr成员。当然,有一些情况我想尽量避免单个实例可能会更改所有实例的属性,因此所有原始指针getter(对于sdk是必需的)都会提供const Bitmap*。不幸的是,现在我甚至不能要求const Bitmap*的宽度,因为Width()是非常量。

我在问自己,解决这个问题的最好方法是什么。我看到三个选项:

  • 完全忘记常量,把一切都变成非常量。在小项目中,我曾经这样做过,但正如我所说,使用更复杂的技术,它会变得更危险。
  • 在任何必要的地方都要做一个就地的。在很多地方都会这样,而且读起来很糟糕。
  • 为3dsmax类编写包装器,这些类至少为可能非常安全的方法提供const方法。这将把所有的const_cast封装在一个地方,也适用于其他项目。

我被警告(我也知道)这可能是基于意见的。但我现在不得不长期处理这个烦人的问题,我真的很想找到一个解决办法,因此需要其他人的经验。


首先,我想说的是,缺乏const的正确性可以通过实现细节来证明,例如getter函数可以对内部同步原语执行锁,因此总是改变内部状态,不能标记为const

1
2
3
4
5
6
7
int Bitmap::Width(void)
{
     int width{};
     ::std::lock_guard<::std::mutex> const lock{m_sync};
     width = m_width;
     return width;
}

作为一种解决方案,您可以编写一个专用的PIMPL位图包装器,用适当的const限定符限制直接访问感兴趣的位图实现转发函数:

1
2
3
4
5
6
7
8
9
10
11
class SharedBitmap
{
    private: ::std::shared_ptr<Bitmap> m_p_bitmap;

    public: int Width(void) const
    {
        return m_p_bitmap->Width();
    }

    // other methods...
};

请注意,这种方法不同于所讨论的第三个选项,因为它不涉及const_cast


根据我(10年)的经验,"const"比它更有用。更不用说代码变长了,所以更难阅读。如果你想知道一个库是如何工作的,你无论如何都要阅读手册,而不是标题。如果你想知道你做得对,你可以运行功能测试。甚至还有静态分析工具来检查是否曾经写入变量,而不必使用无用的非功能元数据来捕获未记录的使用模式来增加代码的负担。因为有很多方法可以打破常量,所以这是捕获此类错误的正确方法。

总之,根据我的经验,方案1是最有效的解决方案。(这是一种意见吗?不同意的人可能会这么认为。)

对于const的快速后清除,您可以执行#define const甚至-Dconst来删除它,尽管它是否安全可能取决于您的具体情况,但对标准头文件执行此操作是非法的。我也做过类似的黑客,比如#define private|protected public,而不是在做白盒测试的时候干扰friend,工作起来很有魅力!

知道在许多编程语言中,"常量变量"的概念是无效的,如果没有它,它们似乎做得很好。

唯一需要常量的时间是C字符串常量/字符串文本。但似乎不是你的情况。