Недавно я столкнулся с неприятным schrödinbug. При попытке загрузить файл в плоское представление памяти, автор написал такой код:Применение правила сглаживания указателя (указатель на самолечение)
class Line final { public:
int stuff[3];
char* data;
}
//...
Line* line = /*...*/;
//Trying to treat line->data like an array. This is *wrong*.
line->data = reinterpret_cast<char*>(line) + 3*sizeof(int);
//...
line->data[0] = /*...*/
line->data[1] = /*...*/
//...
line->data[n] = /*...*/ //"line->data" changes because of this line!
Итак, что происходит в том, что первые строки кода по существу установить line->data
равного &line->data
. Это ошибка, потому что любые изменения значений, на которые указывает line->data
, также могут изменить то, на что указывает line->data
!
Мне было любопытно, что для этого возникла проблема. Мое понимание заключается в том, что, если он не квалифицирован с использованием restrict
(или для g ++/MSVC __restrict
), компилятор должен предположить, что указатели сглажены. Поэтому, если я установил line->data[0]
, чтобы быть чем-то, то он будет видимым для следующего доступа, line->data[1]
и почти наверняка будет недействительным. Тем не менее, в отладчике изменение не было видно до тех пор, пока значительно позже, и записи продолжались долгое время.
Я угадываю, что компилятор (в данном случае MSVC 2013) не учитывал возможность сглаживания. Это разрешено?
Так вы в основном задаете вопрос: «Почему это не произошло на' line-> data [1] = ... '?"? –
Да. Запись через 'line-> data [0]' должна быть видна последующей загрузке 'line-> data' при вычислении' line-> data [1] '- безгласное сглаживание не включает самоиализацию. – imallett
Возможно, из-за заполнения, в зависимости от биты системы. –