Изменение данных без учета квалификатора const
Вопрос
Ранее я уже задавал соответствующий вопрос по этому поводу, поэтому знаю, что это неопределенное поведение.
возврат const char* в char* и последующее изменение данных
string _str = "SDFDFSD";
char* pStr = (char*)_str.data();
for (int i = 0; i < iSize; i++)
pStr[i] = ::tolower(pStr[i]);
У меня была дискуссия по этому поводу с одним из моих коллег.И он сказал мне, что в этом сценарии никаких проблем не возникнет, если я не изменю длину данных.Если я изменю данные, но оставлю такую же длину, это никогда не создаст никаких проблем, поскольку нет возможности std::string
чтобы обнаружить, что данные были изменены.Это не вызовет никаких внутренних противоречий ни в _str
.Так ли это на самом деле?
Решение
Неопределенное поведение Боюсь, его слишком сильно порицали, а упоминания о носовых демонах, похоже, убедили большинство людей в том, что это скорее миф, чем что-либо еще.
Похоже, ваш коллега настолько десенсибилизировал, что для того, чтобы вас убедить, необходимо привести ему конкретные доказательства сути вопроса.К счастью, если у вас есть gcc, это можно сделать:
#include <iostream>
#include <string>
int main() {
std::string const UPPER = "HELLO, WORLD!";
std::cout << "UPPER: " << UPPER << "\n";
std::string lower = UPPER;
for (char* begin = const_cast<char*>(lower.data()),
* end = begin + lower.size();
begin != end;
++begin)
{
*begin = std::tolower(*begin);
}
std::cout << "lower: " << lower << "\n";
std::cout << "UPPER: " << UPPER << "\n";
return 0;
}
Если вы используете gcc, вот что ты получишь:
UPPER: HELLO, WORLD!
lower: hello, world!
UPPER: hello, world! // What the hell ? UPPER was const !!!
Почему ?Поскольку gcc исторически использовал Копирование при записи, и поскольку ты обманул он не обнаружил запись, и поэтому базовый массив хранения является общим.
Примечание:да, это несовместимо с C++11, но мне бы хотелось поработать на C++11.
Другие советы
В соответствии с данные() документация:
Изменение массива символов, доступ к которому осуществляется через данные, является неопределенным поведением.
Значит, ваш коллега не прав, подвоха нет, это неопределенное поведение.То, что происходит, зависит от реализации.
Плохая идея!Вы не можете знать наверняка, как строка реализована на какой-либо текущей или будущей платформе.Например, это может быть совместное использование хранилища с другими объектами, которые чем-то похожи.На некоторых платформах данные могут помещаться в сегмент только для чтения.