8

以下代码与 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;
}
4

7 回答 7

12

我认为相关的报价是:

§ 7.1.6.1 (4) 来自 N3242:

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

这些示例使用const_cast. 正如 James 指出的那样:引用可以在 C++03 标准的第 7.1.5 节中找到。

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

于 2011-08-08T19:49:51.517 回答
7

5.2.11.7:

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

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

于 2011-08-08T19:40:53.420 回答
4

因为您不允许修改声明为 const 的变量。

于 2011-08-08T19:34:55.783 回答
2

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

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

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;
}
于 2011-08-08T19:36:18.413 回答
2

仅仅因为您抛弃了 const,并不意味着您将成功地写入该内存。

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

于 2011-08-08T19:37:37.800 回答
2

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

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

于 2011-08-08T19:50:54.490 回答
1

问题是这一行:

static int const v;

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

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

于 2011-08-08T19:37:22.553 回答