2016-06-07 15 views
5

W ostatnim projekcie wystąpił błąd polegający na tym, że przypadkowo przypisałem float do odwołania do ciągu znaków (zamiast konwertować zmiennoprzecinkową na ciąg, a następnie przypisując go).Przypisywanie wartości zmiennoprzecinkowej do odwołania do ciągu znaków - dlaczego?

Kod wyglądał mniej więcej tak (testowane zarówno pod Xcode/jabłonie LLVM 7.1 i GCC 4.9.2):

#include <iostream> 
using namespace std; 

static void get_text(string &s) { 
    s = 1.0f; // Legal (not even a warning!) 
} 

// This version gives a compiler error (as I'd expect) 
// static void get_text(string &s) { 
//  string out = 1.0f; 
//  s = out; 
// } 

int main() { 
    string s; 
    get_text(s); 
    cout << s << endl; // Prints garbage 
    return 0; 
} 

Drukowanie ciąg oczywiście skutkuje śmieci, ale nie jestem jasne, dlaczego to didn nie dają tyle, co ostrzeżenie. (Domyślam się, że kompilator wykonał jakąś niejawną reinterpretację rzutowania z float, int, na adres pamięci ...?)

Czy istnieje ostrzeżenie, które mogę włączyć (w Xcode, najlepiej), że zapobiegnie tego rodzaju rzeczom w przyszłości?

Odpowiedz

8

To ze względu na wywołanie:

string& operator=(char ch); 

Jest ukryte konwersji z zmiennoprzecinkowych całkowitoliczbowa typu C++ (char to typ całkowity).

Zwykle można użyć -Wfloat-conversion w g ++, aby uzyskać ostrzeżenie o tej konwersji, ale próbowałem go i nie ostrzegał. (? Może kompilator błąd)

prosty sposób zmodyfikować kod, aby uzyskać błędów nieoczekiwanych konwersje pływający/liczba całkowita:

s = { 1.0f }; 

Inną opcją jest, aby funkcja mieć string jako typ zwracany (ogólnie mówiąc ten projekt jest korzystny do posiadania „out” parametr odniesienia tak):

static string get_text() { return 1.0f; } 

Niestety jest to jeden z wielu drobnych pułapek otaczających wykorzystanie std::string, który został „zaprojektowany”, gdy C++ był nadal bardzo Youn g. Nie było oczywiste, jakie niepożądane konsekwencje będą miały w dłuższej perspektywie.

+0

Fascynujące. Ze względu na potomność dodam, że chociaż istnieje 'operator = (char c)' w 'std :: string', to nie ma odpowiedniego konstruktora, który przyjmuje pojedynczą postać --- co wyjaśnia, dlaczego mój druga wersja 'get_text()' w pytaniu nie będzie się kompilować. Jeśli zmienię tę drugą wersję, przeczytaj: 'string out; out = (char) 1.0f; ', to się kompiluje. – s3cur3

Powiązane problemy