2013-09-03 1 views
5

Насколько я знаю, в C++ структуры/члены класса с тем же контролем доступа хранятся в памяти в порядке объявления. Является ли следующий пример m и c должны храниться один за другим:Изменяет ли mutable-член const оптимизацию констант для неперемещаемых членов?

#include <cstdlib> 
#include <iostream> 

struct X 
{ 
    mutable int m; 
    int   c; 
}; 

const X cx = {0, 1}; 

int main() 
{ 
    X& x = const_cast<X&>(cx); 

    x.m = rand(); 
    x.c = rand(); 

    std::cout<<x.m<<" "<<x.c; 
} 

В этом примере программа работает и печатает 2 случайных чисел. Если я удалю mutable, он сработает, потому что cx хранится в защищенной от чтения памяти.

Это заставило меня задаться вопросом - это один mutable член отключить const оптимизацию для всего struct (каким-то образом сделать всех членов mutable)?

Возможно ли хранить части struct в памяти только для чтения и других частях памяти без чтения и уважать стандартную память памяти C++?

Это было протестировано с использованием Visual Studio 2010 в Windows 7 и GCC 4.7.2 на Ubuntu.

ответ

4

Чтобы объяснить, почему компилятор должен делать «все или ничего», когда дело доходит до места хранения struct: В большинстве процессоров страницы памяти составляют 4 КБ (у некоторых есть 8 КБ страниц). Это гранулярность блоков «чтение только» и «чтение/запись». Таким образом, вы не можете иметь одно 4-байтовое целое число в постоянной памяти, а затем следующее 4-байтовое целое число в памяти чтения-записи (если они точно не пересекают границу памяти 4 КБ), но это, безусловно, сделало бы для довольно расточительного использования память, если у вас есть массив из 3000 из них, занимая 12 МБ).

Обратите внимание, что это не «оптимизация». Память только для чтения не быстрее, чем память чтения-записи. Это защита от того, что пользователи глупы с const и записывают данные, на которые они не должны писать.

Также, если вы добавите конструктор, который «что-то делает» для вашего struct, он, скорее всего, сохранит структуру в памяти чтения и записи, потому что компилятор довольно сложно создать код для включения и отключения только для чтения во время выполнения.

+0

Я добавил конструктор X(), который inits m и c и cx не находится в памяти readonly, как это было раньше. Очень интересное понимание, спасибо! – Felics

1

Ключевое слово «const» является скорее ярлыком для команды программиста, как «частный» и «общедоступный», а не директивой компилятора или подсказкой компилятора. Компилятор может использовать его для оптимизации, но не нужно. Компилятор должен только контролировать злоупотребления и предотвращать его. Таким образом, поведение, которое вы видите, полностью в порядке. И нет, невозможно, чтобы части одного экземпляра структуры или экземпляра класса существовали в разных областях памяти (не учитывайте отображение в). Потому что это решение повлияет на использование структуры и должно быть разрешено программистом.

+0

«Ключевое слово« const »- больше ярлык для команды программистов» - боюсь, что в этом случае члены этой команды могут иметь несколько иные мнения относительно того, что означает эта метка. – SChepurin

+0

Я имею в виду, что хорошим объяснением будет: «Спецификатор const - это инструкция для компилятора, чтобы отклонить код, который пытается напрямую изменить этот объект, пытается косвенно косвенно косвенно коснуться объекта ... приводит к неопределенному поведению, что означает, что любой результат возможен «. (http://stackoverflow.com/questions/4275504/deep-analysis-of-const-qualifier-in-c) – SChepurin

+0

Вы правы. Мой ответ был написан в спешке. Тем не менее, это, на мой взгляд, более человечно читаемо. И да, работая в разных командах на протяжении многих лет, я всегда удивляюсь, как люди пытаются обмануть компилятор и рассчитывают на то, что это будет правильно. –

5

Стандартные переговоры о mutable членов во многих местах. Ниже приводятся три части стандарта, поясняющие, что вы можете изменять только mutable членов объекта const. В противном случае это Неопределенное поведение.

3.9.3 CV-классификаторы [basic.type.qualifier]

Объект Const является объектом типа const T или не-изменяемом подобъектом такого объекта.

[...]

7.1.1 спецификаторы класса хранение [dcl.stc]

mutable спецификатора на элементе данных класса аннулирует константный спецификатор, приложенный к содержащему объекту класса и разрешает модификацию класса mutable, хотя остальная часть объекта - const.

[...]

7.1.6.1 СиЗ-классификаторы [dcl.type.cv]

За исключением, что любой член класса объявлен mutable (7.1.1) может быть изменен , любая попытка изменить объект const в течение его срока службы (3.8) приводит к неопределенному поведению .


Можно ли хранить части struct в постоянной памяти и других части на не только для чтения памяти и уважением C++ стандартной раскладки памяти?

Нет, это невозможно хранить частей struct (или class) в другой области памяти, чем остальная часть объекта.

+0

Итак, 'x.c = rand();' в 'main' запускает UB в обоих случаях, правильно? – Hulk

+0

@Hulk Да, ключевое слово 'mutable' на' m' ничего не меняет для 'c'. Посмотрите на это сообщение: http://stackoverflow.com/a/583150/1394283. Это хорошо объясняет последнюю часть стандарта, которую я цитирую. –

 Смежные вопросы

  • Нет связанных вопросов^_^