const变量是否放在只读内存中?

时间:2013-08-05 12:21:26

标签: c++ c const

还是有一些其他保护措施不能修改它们吗?

如果它们在只读存储器中是有意义的 - 这就是使它们成为const的原因,对吗?

9 个答案:

答案 0 :(得分:16)

const是一个编译时构造,在运行时不知道。它只是帮助程序员理解他的程序,并通过改变不应该改变的东西来防止错误的引入。 const告诉编译器您不希望允许更改此变量,因此编译器将强制执行该变量。

答案 1 :(得分:12)

不,他们不是必须的。 const是编译时,允许编译器执行某种优化。但是,并非必须将变量放入只读存储器位置。

请参阅此示例,未定义的行为(感谢Dyp指出这一点):

#include <iostream>

int     main()
{
  const int bla = 42;
  int       *ptr = const_cast<int *>(&bla);

  std::cout << *ptr << std::endl;
  *ptr = 21;
  std::cout << *ptr << std::endl;
}

它会输出4221,但也可能会崩溃。

现在看看这个:

#include <iostream>

int     main()
{
  const int bla = 42;
  int       *ptr = const_cast<int *>(&bla);

  std::cout << bla << std::endl;
  *ptr = 21;
  std::cout << bla << std::endl;
}

在我的编译器上,此输出4242,因为编译器进行了一些优化。请注意,由于*ptr = 21;

,它仍然可能会崩溃

答案 2 :(得分:5)

在很多情况下,编译器无法将const转换为只读内存(假设系统中首先存在只读内存)。实际上,我相信几乎所有编译器通常都会使const个对象存在于常规数据(或堆栈)内存中,就像普通变量一样。

const的主要目的是使用您不想要的编译器声明您的意图,并且不应该更改某些值。我没有看到为什么编译器在有限的情况下不能将const变量放在只读内存中的原因。但我也不会依赖于此 - 标准肯定会使这成为可能,因为它提到使用const_cast从最初标记为const的对象中删除const,然后写入它是未定义的行为(因此,它不需要编译器在使用const_cast删除原始const后允许修改该值 - 因此允许“崩溃,因为我们试图写只读内存“)。

但请考虑一下:

class X
{
   int x;
  public:
   X(int v) : x(v) {}
}

int c = rand();

const X a(c+1);
const X b(c+2); 

在这种情况下,编译器无法知道crand获得的值,因此无法在编译时初始化ab时间。

答案 3 :(得分:2)

就标准而言,没有要求将const变量放入写保护的RAM中。 const基本上只是编译器强制执行的文档。

实际上,如果值可以在编译时完全计算,编译器通常会使用const变量的只读存储。否则,它们将被置于与其他所有内容相同的读写堆栈或堆栈中。

答案 4 :(得分:2)

没有。考虑具有const成员的mutable对象。如上所述,const是一个编译时构造,以帮助程序员传达意图。

答案 5 :(得分:2)

const关键字有两种用途:

  1. 众所周知的“我保证不会修改此对象的状态”
  2. 作为一项特殊规则,编译器可以将定义为const的对象放在只读内存中,只要该对象没有mutable成员(即整个object是对象的状态。)
  3. 这就是为什么允许const_cast剥离const限定符的原因,但要求是对象定义本身不是constWikipedia on const correctness声明“但是,根据ISO C ++标准,任何修改通过const_cast自身声明为const的对象的尝试都会导致未定义的行为。”。

答案 6 :(得分:2)

C ++标准不仅不保证const对象在只读存储器中,而且实现完全难以实现,如下所述。

C ++实现很难放置具有自动存储持续时间的const个对象,其地址是在只读内存中获取的。这是因为每个不同的对象必须具有不同的地址(因为它们的指针必须比较不相等)。因此,每次执行它所在的块时,都必须创建每个这样的对象。

如果未采用const对象的地址,编译器可以仅使用内存中的单个实例来实现它的多个实例(在C ++计算模型中)(因为每个实例都是相同的并且不会更改) 。因此,这样的对象可以在程序启动时创建一次(可能通过从程序文件的常量数据部分加载),标记为只读,并在程序执行期间保持不变。但是,如果获取对象的地址(并以可观察的方式使用),则编译器必须创建对象的每个单独实例(或者以某种方式“伪造”一个实例具有多个地址)。通常,编译器不能预测可以同时存在多少块的执行(例如,当存在递归函数调用时)。因此,它无法在程序启动时创建所需的对象的所有实例。它们必须在运行中创建。

创建对象需要修改内存,以编写对象的初始值。因此,将具有自动存储持续时间的const对象放入只读存储器中需要频繁地将内存从只读更改为可写和返回。要创建新对象,程序必须将只读内存更改为可写内存,写入新对象的初始值,然后将内存更改回只读。

此外,这将仅为没有信号处理程序的单线程程序提供只读内存的外观。具有多个执行线程的程序或单个处理程序可能能够在处于可写状态时观察内存。

答案 7 :(得分:1)

如果它们在只读内存中,它会阻止const_cast有用且有意义,因此这样的代码是不可能的,将const变量传递给具有非{的函数{1}}参数: -

const

请注意,print函数实际上可以更改最初定义的void print (char * str) { cout << str << endl; } int main () { const char * c = "test text"; print ( const_cast<char *> (c) ); return 0; } 变量const中的值。

答案 8 :(得分:1)

const是编译器的标记。在编译期间,编译器将常量添加到单独的组中,并检查是否尝试更改它。如果某些函数尝试这样做,您将收到编译器错误。

然而,有可能技巧编译器并使用指针和const更改const_cast值,但是由于这个原因,你不是编译器而是自己(或同事)。

正如我所说,对我一直在寻找如何改变const价值的朋友。 const不仅适用于编译器,对于开发人员而非编译器更多,因为它显示了哪些数据不会被更改。