【问题标题】:const_cast of a static const member静态 const 成员的 const_cast
【发布时间】:2011-10-22 16:24:03
【问题描述】:

以下代码在 GCC (4.2-4.6) 和 Clang (2.1) 下都能很好地编译,但是当我运行可执行文件时,它给了我“总线错误:10”。我不明白原因。

#include <iostream>

struct A
{
  static int const v;
  A() { ++*const_cast<int *>(&A::v); }
};

int const A::v = 0;

int main(int argc, char * argv[])
{
  A a, b, c;
  std::cout << a.v << std::endl;

  return 0;
}

【问题讨论】:

  • 我很确定修改你声明为 const 的东西是未定义的行为,但我相信有人可以挖掘出准确的陈述。
  • +1 用于提供最小的完整示例程序。有关详细信息,请参阅sscce.org

标签: c++ static constants member const-cast


【解决方案1】:

我认为相关的引用是:

N3242 中的第 7.1.6.1 (4) 节:

除了声明为 mutable 的任何类成员都可以修改外,任何 尝试在其生命周期内修改 const 对象会导致 未定义的行为。

这些示例使用const_cast 说明了这一点。正如 James 指出的那样:引用可以在 C++03 标准的 §7.1.5 中找到。

稍微详细说明一下:当声明 const 时,该语言规则允许编译器使用只读内存(如果它在目标架构上可用)。如果没有这条规则,const-ness 总是可以被抛弃而不必担心任何后果,并且使用它只是开发人员纪律的问题。它的方式至少可以告诉人们他们正在调用 UB,这通常是一个很好的威慑。 const_cast 本身无关紧要,因为无论您如何欺骗编译器让您操纵 const 对象,这并不重要。

【讨论】:

    【解决方案2】:

    5.2.11.7:

    根据对象的类型,通过 由 const_cast 产生的指针、左值或指向数据成员的指针 丢弃 const 限定符)可能会产生未定义的行为 (7.1.5.1)

    在您的情况下,您正在尝试修改只读段中的数据。

    【讨论】:

    • 这是一个非规范性注释(即它仅供参考)。规范性文本在引用的 §7.1.5.1 中。
    • 草案第 7.1.6.1 条。看我的回答。
    • @pmr:对,因为 C++0x 规范添加了一个定义 constexpr 的子句。
    【解决方案3】:

    因为你不能修改声明为 const 的变量。

    【讨论】:

      【解决方案4】:

      仅仅因为你抛弃了 const,并不意味着你会成功地写入那个内存。

      const_cast&lt;T&gt; 所做的只是从编译器的角度移除变量的 const-ness。这让编译器继续并发出代码以写入变量。但是在运行时,如果编译器/链接器碰巧将变量放入只读内存,那么无论你如何转换,硬件都会阻止你在那里写入。

      【讨论】:

        【解决方案5】:

        我没有解决实际问题的方法。我只能说,不要使用const_cast,除非打算从非常量成员函数调用 const 成员函数并将 const 结果“const_cast”(使其成为非常量成员函数的可变结果)。

        但是我有一个改进你的设计的建议:

        class A
        {
        private:
          static int v;
        public:
          A() { ++v; }
          static int get_v() { return v; }
        };
        
        int A::v = 0;
        
        int main(int argc, char * argv[])
        {
          A a, b, c;
          std::cout << a.get_v() << std::endl;
        
          return 0;
        }
        

        【讨论】:

          【解决方案6】:

          基本上,如果一个变量被声明为const,编译器就可以将结果发送到只读内存。获取const 对象的指针/引用,然后使用const_cast 删除const 可能会导致未定义的行为。

          一般来说,只有当被引用的对象不是const 时才使用const_cast 是安全的(即使您拥有的指针/引用是const)。

          【讨论】:

            【解决方案7】:

            问题是这一行:

            static int const v;
            

            因为您将其声明为 const,所以 const_cast 会导致未定义的行为 - 在您的情况下,您很幸运遇到了总线错误(这是我系统上的分段错误)。

            声明它是非const的,你可以毫无问题地调用它的const_cast。

            【讨论】:

              猜你喜欢
              • 2020-07-04
              • 2020-07-16
              • 1970-01-01
              • 2013-04-11
              • 1970-01-01
              • 1970-01-01
              • 2012-12-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多