2015-11-18 10 views
10

Ich versuche, die hässliche std::string::operator=(char) Überladung irgendwie zu deaktivieren/zu markieren (die meiner Erfahrung nach nur verwendet wird, wenn man eine ganze Zahl fälschlicherweise einer Zeichenkette zuordnet und subtile und schwierige Fehler verursacht).Wie markiert man eine * Standard-Bibliothek * -Funktion/-Methode in meinem Projekt als veraltet (oder überhaupt nicht mehr)?

Ich habe versucht, mit:

  • eine explizite Spezialisierung mit einer statischen assert darin

    #include <string> 
    #include <type_traits> 
    
    template<> std::basic_string<char> &std::basic_string<char>::operator=(char c) { 
        static_assert(false, "Don't use this!"); 
    } 
    

    , die nicht als <string> bereits tut eine explizite Instanziierung std::string

  • das [[deprecated]] Attribut, auf eine ähnliche Erklärung wie oben in verschiedenen Positionen angewendet; keine Position, die ich versuchte, schien ein vernünftiges Ergebnis zu liefern;
  • =delete, die aus ähnlichen Gründen versagt;
  • Ich dachte über die Verwendung von Linker Tricks (in ähnlicher Weise, in dem gleichen Projekt haben wir Laufzeitüberprüfungen auf setlocale Nutzungen mit der --wrapld Linker-Option), aber die Tatsache, dass dies eine Vorlage und Inline-Methode ist kompliziert die Angelegenheit.

Nun zu den Fragen:

  • gibt es eine Standardmethode, um irgendwie zu deaktivieren jede Funktion oder Methode in der Standardbibliothek (lesen (wie bei =delete passieren würde): in einer Bibliothek, wo man nicht ändern die Deklarationen in den Kopfzeilen)?
  • wie oben, aber, statt deaktivieren, eine Warnung hinzufügen (wie mit [[deprecated]] passieren würde);
  • versagt die Standardmethode, gibt es etwas g ++ - spezifisch?
  • Wenn es keine "allgemeine" (= für jede Methode, jede Klasse, jede Funktion, ...) Lösung gibt, gibt es etwas, das wir auf diesen speziellen Fall anwenden könnten (= eine Methode einer Template-Klasse möglicherweise deaktivieren auch nur eine bestimmte Instantiierung)?
+1

Sie haben eine lustige Definition von "veraltet", wenn Sie versuchen, eine statische Assert oder eine gelöschte Funktion zu verwenden. –

+0

@ JonathanWakely: "insgesamt veraltet oder deaktiviert"; aber soweit es mich betrifft, ist es im Wesentlichen das Gleiche, ich würde wahrscheinlich "-Werror" auf eine solche Warnung verwenden, es gibt keinen triftigen Grund, diesen Zuweisungsoperator zu verwenden (genau wie es keinen Grund gibt, sagen zu können, "bekommt" 'oder die String-Literal =>' char * 'Konvertierung neben Legacy-Code-Kompatibilität). –

Antwort

4

Sie können folgende Compiler/Linker-Option verwenden:

$ g++ -O0 test.cpp -Wl,--wrap=_ZNSsaSEc 

Erläuterung:

Die _ZNSsaSEc ist die ergänzten Namen Ihrer säumige Funktion:

$ echo _ZNSsaSEc | c++filt 
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char) 

Die -Wl Compiler-Option soll Optionen an den Linker übergeben.

Und die Linkeroption --wrap=<symbol> transformiert jeden Verweis auf das gegebene Symbol auf die Alternative __wrap_<symbol>. Und da Sie sind (hoffentlich) nicht eine Funktion namens __wrap__ZNSsaSEc definieren, werden Sie einen schönen Linker Fehler:

test.cpp:(.text+0x26): undefined reference to `__wrap__ZNSsaSEc' 

und -O0 ist Optimierungen zu deaktivieren und den Compiler von inlining die Funktion zu verhindern.Der Linker-Trick funktioniert nicht, wenn Inlining ist, wie @SergeBallesta im Kommentar darauf hingewiesen hat.

Vielleicht ein bisschen wie ein Hack, aber hey, es funktioniert!

+1

@SergeBallesta: Nun, mit "-O0" funktioniert es. Mit '-O1' oder höher tut es das nicht. – rodrigo

+0

Tun Sie das nicht! Es ist absolut nicht offensichtlich, dass dieser Fehler auf einen falsch verwendeten Zuweisungsoperator zurückzuführen ist. Ein paar Jahre später könnte diese Linker-Flagge selbst ein schwer zu verfolgender Fehler sein. – Richard

1

Nun, ich befürchte, dass die Standardbibliothek Standard sein soll, und als solche keine Hooks zur Verfügung stellt, um Entwicklern zu erlauben, es zu zwicken.

Ein hässlicher Weg (sag nie I rate dir, es zu benutzen ;-)) wäre die Tatsache, dass Standard Library Header nur Textdateien sind, so dass Sie sie leicht in Ihrer lokalen Entwicklungsumgebung ändern können. Ein möglicherweise weniger schlechter Weg wäre, einen Ordner einzurichten, der Links zu den ursprünglichen Headern mit Ausnahme des geänderten Headers enthält, und den Compiler anzuweisen, diesen Ordner für Systemheader zu verwenden.

Auf diese Weise können Sie alles, was Sie wollen ändern, aber ... Portabilität und Wartbarkeit ... Es ist wirklich eine Desperado Lösung ...

+0

Der erste Satz ist ein wenig strittig; nehmen Sie eine dynamische Sprache Ihrer Wahl (Javascript, Python, Ruby, ...)), da ist * eine Standardbibliothek, aber Sie können es auf die bizarrsten Weisen drehen; Außerdem bietet die C++ - Standardbibliothek Anpassungspunkte (als Vorlagenargumente oder als "offene Funktionen", denke 'std :: hash'), POSIX und Win32 erlauben die bedingte Aufnahme von Stuff über Makros und alle konkreten Implementierungen von C++ erlauben Flags oder Anpassungen an die Standardbibliothek und sogar an die Sprache selbst (als Kompilierzeitschalter für den Compiler, als zu definierende Makros, ...). –

0

Dies ist Klirren ++ spezifisch, da ich nicht weiß, was Die entsprechende Funktionalität wird in der gnu toolchain aufgerufen. Es ist auch etwas übertrieben.

Rodrigos Vorschlag, den Linker zum Austauschen des Symbols zu verwenden, ist ideal für Nicht-Inlined-Fälle. Wenn Sie gelegentlich alles bei O0 bauen, reicht das aus.

Andernfalls bietet die llvm (Clang) Toolchain überraschend viel Kontrolle über die Optimierungspipeline. Beispielsweise können Sie ohne Optimierungen kompilieren, dann die Optimierungen selbst mit opt ​​ausführen und dann in eine Objektdatei konvertieren.

clang++ -c test.cpp -O0 --emit-llvm test.ll 
opt -O3 test.bc -o faster.ll 
clang++ -c faster.bc -o test.o 

Das opt-Tool ist erweiterbar. Ich kann nicht ehrlich sagen, es ist trivial zu erweitern, aber der Prozess ist gut dokumentiert. Sie können einen Compiler-Durchlauf schreiben, der warnt, wenn Ihre Standardbibliotheksfunktion angezeigt wird. Das Endergebnis könnte so etwas wie aufgerufen werden:

clang++ -c test.cpp -O0 --emit-llvm test.ll 
opt --load DeprecationPass.so test.bc -o /dev/null 
opt -O3 test.bc -o faster.ll 
clang++ -c faster.bc -o test.o 

Wenn Sie die benutzerdefinierte sicher sind, Pass korrekt ist (nicht nur nützlich) Sie einen einzigen Aufruf von opt verwenden können. Es ist wahrscheinlich möglich, Flags durchzugehen, um über das clang-Frontend zu entscheiden, aber es ist nicht sofort offensichtlich, wie.

Insgesamt ist Rodrigos Vorschlag, gelegentlich das gesamte Produkt bei O0 zu bauen, wahrscheinlich ein besserer Plan - aber es ist aufregend, dass Sie mit clang so etwas machen können.