So vermeiden Sie implizite Konvertierungen von int (0) in Zeiger in einem Vektor

9

Es gibt eine Situation, in der ich alle Knotennamen eines Pfads zu einem Schlüssel in JSON sammeln möchte. Bedenken Sie, dass die Bedingung des Array-Index "0", "1" ebenfalls zulässig ist, aber es ist leicht, die Anführungszeichen zu vergessen, was zu einem Absturz führen würde, wenn eine Dereferenzierung durchgeführt wird. Also möchte ich das ablehnen. Beispiel:

#include <vector>
#include <iostream>

int func(const std::vector<const char*>& pin) {
    return pin.size();
}

int main() {
    // {"aname", "3", "path", "0"} wanted but this still compile
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

Ich habe dies gefunden und ausprobiert. Wie vermeide ich implizite Konvertierungen für nicht konstruierende Funktionen? wie folgt:

#include <vector>
#include <iostream>

int func(const std::vector<const char*>& pin) {
    return pin.size();
}

template<typename T>
int func(T pin) = delete;

int main() {
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

Aber der Compiler hat mich immer noch nicht verstanden.

Irgendein Vorschlag?
Bitte weisen Sie auf einen Missbrauch von Terminologien und Annahmen hin, danke!

Rustyhu
quelle
Gibt es einen Grund, warum Sie std::vector<const char*>anstelle von verwenden std::vector<std::string>>?
Bolov
Willst du auch verbieten nullptr?
Jarod42
@bolov Zu Beginn denke ich darüber nach, diese Knotennamen an eine JSON-Analyseschnittstelle zu übergeben, die char * im C-Stil als Eingabe verwendet, dies ist hier jedoch nicht beschränkt. Ich habe getestet, mit std :: vector <std :: string >> akzeptiert beim Kompilieren immer noch 0, stürzt aber beim Ausführen ab. Auf meinem Computer meldet GCC "basic_string :: _ M_construct null ungültig".
Rustyhu
@ Jarod42 Ja, was Sie wollen, ist ein String-Literal im C-Stil.
Rustyhu

Antworten:

9

Etwas wie das? Es ist der von Ihnen vorgeschlagenen Überladungslösung sehr ähnlich, erfordert jedoch das Umschließen des Vektortyps. Kann nicht erstellt werden, wenn Sie ein Literal angeben, 0da die gelöschte Konstruktorüberladung ausgewählt ist.

#include <memory>
#include <new>
#include <vector>
#include <iostream>
using std::vector;

template<typename T>
struct no_zero {
        no_zero(T val) : val(val) {}
        no_zero(int val) = delete;
        operator T() { return val; }
        T val;
};

int func(const vector<no_zero<const char*> >& pin) {
    return pin.size();
}

int main() {
    // {"aname", "3", "path", "0"} wanted but this still compile
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}
Mikel Rychliski
quelle
4

Im Nachhinein sind viele der impliziten Konvertierungen in C ++ unglücklich, dies ist eine davon.

Eine Option, die in Betracht gezogen werden sollte, ist -Wzero-as-null-pointer-constantgcc und clang. Seien Sie vorsichtig, da dies das Verhalten von Standardprogrammen ändert und bei globaler Aktivierung einige unbeabsichtigte Auswirkungen haben kann.

g ++ - Wie deaktiviere ich die implizite Konvertierung von 0 in Zeigertypen?

Welche Clang-Warnung entspricht der Null-Zeiger-Konstante Wzero von GCC?

Bolov
quelle