Сегодня мой коллега обнаружил очень тонкий баг в нашем коде, который в основном шел следующим образом:
double d = 65;
std::string s = "Hello world";
// .. somewhere later, accidentally assigning to s instead of a similarly
// named numerical variable.
s = d;
// s is now 'A'
Причина, по которой эта ошибка может возникнуть, я обнаружил, что std::basic_string<_Elem>
имеет оператор присваивания
_Myt& operator=(_Elem _Ch)
{ // assign 1 * _Ch
return (assign(1, _Ch));
}
Теперь компилятор действительно не жалуется (много, он выдает предупреждение о сужении конверсии, если уровень достаточно высок). Кажется, мы поймали эту ошибку достаточно рано, чтобы она не наносила большого ущерба, но мне было интересно, почему это разрешено. В конце концов, я не могу писать
std::string s = 65;
потому что std::string
не имеет (n неявного) конструктора, который принимает char
. Не было бы безопаснее сделать это явным преобразованием, которое заставляет вас писать
std::string s = string('A');
и это будет запрещено назначать одному _Elem
(char
).
Есть ли причина, по которой этот оператор присваивания был предоставлен? Как заметил тот же коллега,
double d;
char c = d;
допускается, тогда как
int* p = d;
не является (для любого размера указателя) - предположительно потому, что неявное преобразование из числа в указатель считается опасным. Фактически, он даже, кажется, превратил его в С++ 11, который, насколько я видел, пытается быть довольно строгим и полезным в управлении типом данных.