【问题标题】:const_cast vs reinterpret_castconst_cast 与 reinterpret_cast
【发布时间】:2012-12-25 16:55:56
【问题描述】:

参考 SO C++ 常见问题解答When should static_cast, dynamic_cast and reinterpret_cast be used?

const_cast 用于将 const 删除或添加到变量中,它是唯一可靠、已定义且合法的删除 const 的方法。 reinterpret_cast 用于改变一个类型的解释。

我以合理的方式理解为什么 const 变量应该仅使用 const_cast 强制转换为非 const,但我无法找出使用 reinterpret_cast 而不是 const_cast 添加 const 的合理理由。

我知道使用 reinterpret_cast 来添加 constness 是不明智的,但是使用 reinterpret_cast 来添加 constness 会是 UB 还是潜在的定时炸弹?

我在这里感到困惑的原因是因为声明

很大程度上,使用 reinterpret_cast 获得的唯一保证是,如果 您将结果转换回原始类型,您将得到准确的 相同的值。

因此,如果我使用 reinterpret_cast 添加 constness,并且如果您将结果 reinterpret_cast 重新转换为原始类型,它应该返回原始类型并且不应该是 UB,但这违反了一个事实,即应该只使用 const_cast 来删除恒常性

在单独的说明中,该标准保证您可以使用重新解释大小写来添加 Constness

5.2.10 Reinterpret cast (7) ......当“pointer to T1”类型的prvalue v转换为“pointer to cv T2”类型时,结果为 static_cast(static_cast(v)) 如果 T1 和 T2 都是 标准布局类型 (3.9) 和 T2 的对齐要求是 不比T1严格…………

【问题讨论】:

  • @clossvoters:您能否请我参考回答此问题的重复问题?
  • const_cast 还包括添加/删除volatile
  • @MikeDeSimone:肯定是的,但我目前的重点只是 constness
  • 那个语句应该写成"...如果你reinterpret_cast把结果变回原来的类型..."

标签: c++ casting constants reinterpret-cast


【解决方案1】:

reinterpret_cast 更改对象内数据的解释。 const_cast 添加或删除 const 限定符。数据表示和常数是正交的。所以有不同的演员关键字是有意义的。

因此,如果我使用 reinterpret_cast 添加 constness,并且如果您将结果 reinterpret_cast 重新转换为原始类型,它应该返回原始类型并且不应该是 UB,但这违反了一个事实,即应该只使用 const_cast 来删除恒常性

那甚至无法编译:

int * n = new int;
const * const_added = reinterpret_cast<const int *>(n);
int * original_type = reinterpret_cast<int*>(const_added);
    // error: reinterpret_cast from type ‘const int*’ to type ‘int*’ casts away qualifiers

【讨论】:

  • 参考5.2.10 Reinterpret cast:When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast&lt;cv T2*&gt;(static_cast&lt;cv void*&gt;(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1.。所以看来你可以使用 reinterpret cast 添加 constness。
  • 非 const 对象总是可以隐式转换为 const 而无需任何强制转换。我不明白为什么reinterpret_cast 应该是这条规则的例外。
【解决方案2】:

您不应该只是constreinterpret_cast 相加。 reinterpret_cast 应该主要是:重新解释指针(或其他)。

换句话说,如果您要从const char* 变为char*(希望是因为您无法更改糟糕的API),那么const_cast 是您的朋友。这就是它的全部意图。

但是如果你需要从MyPODType*const char*,你需要reinterpret_cast,而且不需要const_cast 就很好了。

【讨论】:

    【解决方案3】:

    我能想到的将 reinterpret_cast 与 const 相关联的唯一地方是将 const 对象传递给接受 void 指针的 API -

    UINT ThreadFunction(void* param)
    {
        const MyClass* ptr = reinterpret_cast<const MyClass*>(param);
    }
    

    【讨论】:

      【解决方案4】:

      要记住一件事:不能使用const_cast 使const 变量可写。如果 const 引用引用非 const 对象,则只能使用它从 const 引用中检索非 const 引用。听起来很复杂?示例:

      // valid:
      int x;
      int const& x1 = x;
      const_cast<int&>(x1) = 0;
      // invalid:
      int const y = 42;
      int const& y1 = y;
      const_cast<int&>(y1) = 0;
      

      实际上,这两种方法都可以编译,有时甚至可以“工作”。但是,第二个会导致未定义的行为,并且在许多情况下会在将常量对象放入只读内存时终止程序。

      也就是说,还有几件事:reinterpret_cast 是最强大的演员阵容,但也是最危险的演员,所以除非必须,否则不要使用它。当您需要从void* 转到sometype* 时,请使用static_cast。反方向时,使用内置的隐式转换或使用显式的static_cast。与添加或删除 const 类似,这也是隐式添加的。关于reinterpret_cast,另请参阅C++ When should we prefer to use a two chained static_cast over reinterpret_cast 的讨论,其中讨论了一种不那么骇人听闻的替代方案。

      乌力

      【讨论】:

        【解决方案5】:

        是的,如您所知, const_cast 意味着它从特定类型中删除 const 。

        但是,当我们需要为一个类型添加常量时。我们有理由这样做吗?

        例如,

        void PrintAnything(void* pData)
        {
            const CObject* pObject = reinterpret_cast<CObject*>(pData);
            // below is bla-bla-bla.
        }
        

        reinterpret_cast 与 'const' 无关。

        const_cast 意味着两件事。 第一个是从类型中删除常量,另一个是赋予其代码明确性。因为你可以使用 C 风格的 cast 来使用它,但这不是明确的,所以不推荐。

        它们的功能不同。绝对不一样。

        【讨论】:

          猜你喜欢
          • 2010-09-24
          • 1970-01-01
          • 2013-07-15
          • 2012-07-23
          • 1970-01-01
          • 2018-07-14
          相关资源
          最近更新 更多