还是有一些其他保护措施不能修改它们吗?
如果它们在只读存储器中是有意义的 - 这就是使它们成为const
的原因,对吗?
答案 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;
}
它会输出42
和21
,但也可能会崩溃。
现在看看这个:
#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;
}
在我的编译器上,此输出42
和42
,因为编译器进行了一些优化。请注意,由于*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);
在这种情况下,编译器无法知道c
中rand
获得的值,因此无法在编译时初始化a
和b
时间。
答案 3 :(得分:2)
就标准而言,没有要求将const
变量放入写保护的RAM中。 const
基本上只是编译器强制执行的文档。
实际上,如果值可以在编译时完全计算,编译器通常会使用const
变量的只读存储。否则,它们将被置于与其他所有内容相同的读写堆栈或堆栈中。
答案 4 :(得分:2)
没有。考虑具有const
成员的mutable
对象。如上所述,const是一个编译时构造,以帮助程序员传达意图。
答案 5 :(得分:2)
const
关键字有两种用途:
const
的对象放在只读内存中,只要该对象没有mutable
成员(即整个object是对象的状态。)这就是为什么允许const_cast
剥离const限定符的原因,但要求是对象定义本身不是const
。 Wikipedia 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
不仅适用于编译器,对于开发人员而非编译器更多,因为它显示了哪些数据不会被更改。