Fehlermeldung bei globalem vector-Objekt vom Typ string
-
Die Fragen von @Yadgar sind doch Spam... Ich kann hier keine gebotene Sorgfalt erkennen.
Es tritt ein Fehler auf... ja, toll. Weder die genaue Fehlermeldung, noch der Code, noch der Kontext wird angegeben.
@Yadgar Sollen das nur Provokationen sein?
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
Innerhalb von main()
Wo ist die schließende Klammer?
-
errormsgs.push_back("Befehl unbekannt!");Das steht im Nirgendwo. Lektion 0 in C++: Code muss in Codeblöcken stehen. Vielleicht möchtest du dir mal angucken, wie man die Werte von Vectoren bei deren Definition setzt? Oder noch viel besser: Vermeide Anti-Patterns wie veränderliche globale Objekte gleich ganz. Da wirst du nur unglücklich mit.
-
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
#include <string.h> #include <vector> ... vector<string> errormsgs; // Liste der Fehlermeldungen errormsgs.push_back("Befehl unbekannt!"); // in parse()Gleich vorweg: Du möchtest wahrscheinlich
#include <string>und nicht#include <string.h>verwenden. Ersteres holtstd::stringherein, letzteres ist für C String-Functionen wiestrcpyund so'n Kram. Wenn das bei dir nicht zu einem Fehler geführt hat, dann ist das purer Zufall, z.B. weil ein anderer Headerstd::stringfür dich eingebunden hat.Zu deinem Problem: Du kannst keine "Statements" zwischen den Funktionen schreiben, nur Deklarationen, Definitionen und Variablen-Initialisierungen. Wenn du möchtest, dass
errmsgseinen Default-Eintrag bekommt, dann muss du den in einer Initialisierung erzeugen. z.B. so:// Liste der Fehlermeldungen vector<string> errormsgs = { "Befehl unbekannt!" };Das ist m.E. die sauberste Form für so einen simplen Default-Eintrag. Für komplizierteres kann man auch mithilfe einer Lambda-Funktion initalisieren. Damit kommt man darum herum, dass man nicht einfach "zwischen die Funktionen" irgendwelche
v.push_back()-Funtkionen aufrufen kann:// Liste der Fehlermeldungen vector<string> errormsgs = []{ vector<string> init; init.push_back("Befehl unbekannt!"); return init; }();Info: Das "()" am Ende ist wichtig, damit wird nämlich die Lambda-Funktion direkt aufgerufen und der
vectormit dem Rückgabenwert initialisiert (Copy-Konstruktion). Merke: das ist immer noch eine Initialisierung, man kann da durchaus Funktionen in dieser Form aufrufen, nur nackte Funktionsaufrufe ohne Initialisierung sind nicht erlaubt.Alternativ geht auch so was (ich finde das mit der Lambda-Funktion allerdings eleganter, weil es alles kompakt zusammenhält):
auto init_errormsgs() { vector<string> init; init.push_back("Befehl unbekannt!"); return init; } vector<string> errormsgs = init_errormsgs();Ansonsten: Wenn du nicht unbedingt dynamische Strings benötist, kannst du für solche Fehlermeldungen auch statische Strings verwenden. Eine moderne C++-Variante wäre z.B. diese hier:
#include <vector> #include <string_view> using namespace std; // Liste der Fehlermeldungen vector<string_view> errormsgs = { "Befehl unbekannt!" };Das kann man so machen, weil solche String-Literale direkt in das Programm eingebettet werden und
char*-Pointer auf diese für die gesamte Laufzeit des Programms gültig bleiben. Das ist auch insofern effizienter, da in dieser Form der Compiler denvectordirekt in der.data-Section des Programms anlegen kann und dieser dann nicht bei der Programminitialisierung konstruiert werden muss (etwas weniger Arbeit und kompakter in der Executable). Für dynamische Strings erzeugt der Compiler nämlich einen versteckten "Global Constructor", der dann beim Start des Programms automatisch vormain()aufgerufen wird, und der vielleicht so aussehen könnte:void __GLOBAL_construct_errormsgs() { errormsgs.push_back("Befehl unbekannt!") }Ein statisches Objekt hingegen, wie der
string_view-Vektor würde stattdessen direkt fertig konstruiert geladen und benötigt eine solche Funktion nicht. Das ist nur ein relativ nebesächliches Detail, aber vielleicht ganz interessant zu wissen (das ist mir nur gerade sehr präsent, weil ich in meinem derzeitigen Hobbyprojekt um jedes Byte in der Binary kämpfe
).
-
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
int main(int argc, char* argv[])
{
vector<string> commands; // Liste der Befehle in yaigat
commands.push_back("-help");
commands.push_back("-e");
commands.push_back("-engine");
commands.push_back("-p");
commands.push_back("-prompt");
commands.push_back("-pm");
commands.push_back("-promptmagic");
commands.push_back("-rs");
commands.push_back("-randomseed");
commands.push_back("-fs");
commands.push_back("-fixedseed");
commands.push_back("-m");
commands.push_back("-model");
commands.push_back("-rt");
commands.push_back("-runtime");
commands.push_back("-w");
commands.push_back("-weight");
commands.push_back("-s");
commands.push_back("-style");
commands.push_back("-a");
commands.push_back("-average");
commands.push_back("-as");
commands.push_back("-averagesequence");
commands.push_back("-c");
commands.push_back("-count");
commands.push_back("-cq");
commands.push_back("-countquotient");Mein Vorschlag wäre, dass Du das wie folgt änderst, wenn während der Laufzeit nichts mehr dazu kommt.
// N == Anzahl der Befehle in commands static constexpr std::array<std::string_view, N> commands = { "-help", "-e", "-engine", ... }; int main() {
-
@john-0 sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
static constexpr std::array<std::string_view, N> commandsJa. Das ist noch besser.
std::vectorecht nur wenn die Einräge dynamisch sein müssen (zur Laufzeit hinzufügen oder entfernen). Auch fürerrormsgs.
-
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
#define STBI_NO_BMP
#define STBI_NO_PSD
#define STBI_NO_HDR
#define STBI_NO_PIC
#define STBI_NO_PNM//#include <stdlib.h>
#include <iostream>
//#include <string.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
//#include <stb/stb_image.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
//#include <stb/stb_image_write.h>Die nicht auskommentierten Präprozessordirektiven verstehe ich (alle) nicht und ich bin mir fast sicher, dass daran etwas falsch sein muss...
Die
STBI_NO_...-Direktiven sind offizielle Flags vonstb_image.h. Da diese vor der Implementierung definiert werden, werden die entsprechenden Decoder (BMP, PSD, HDR, PIC und PNM) gar nicht erst kompiliert. Das spart Platz in der finalen ausführbaren Datei. Aktiv bleiben damit standardmäßig noch beliebte Formate wie PNG, JPEG, GIF und TGA.Empfehlung:
// 1. Standard-Header #include <iostream> #include <vector> // 2. Feature-Flags für stb_image #define STBI_NO_BMP #define STBI_NO_PSD #define STBI_NO_HDR #define STBI_NO_PIC #define STBI_NO_PNM // 3. Implementierung & Header laden (Pfade ggf. anpassen!) #define STB_IMAGE_IMPLEMENTATION #include "stb/stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb/stb_image_write.h"Und beachte: Die Definitionen von
STB_IMAGE_IMPLEMENTATIONundSTB_IMAGE_WRITE_IMPLEMENTATIONdürfen insgesamt nur in genau einer einzigen.cpp-Datei des Projekts stehen, da es sonst zuDublicate Symbol-Fehlern beim Linken kommt.
-
@SeppJ sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
errormsgs.push_back("Befehl unbekannt!");Das steht im Nirgendwo. Lektion 0 in C++: Code muss in Codeblöcken stehen. Vielleicht möchtest du dir mal angucken, wie man die Werte von Vectoren bei deren Definition setzt? Oder noch viel besser: Vermeide Anti-Patterns wie veränderliche globale Objekte gleich ganz. Da wirst du nur unglücklich mit.
O.k., dann werde ich das Fehlermeldungs-Vector-Array jedesmal genauso wie die Befehlsliste per Referenz übergeben (müssen) - sieht zwar plump aus, aber dürfte zumindest funktionieren! Und was die weiteren Postings angeht (Lambda-Funktion)... ich glaube, ich will mein C++ von 1998 wiederhaben! Breymann, oder allenfalls noch Aupperle...
-
Was ist mit structs? Ich sage schon mal gleich, dass mehr als drei Parameter ein Anti-Pattern, also falsch ist.
-
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
O.k., dann werde ich das Fehlermeldungs-Vector-Array jedesmal genauso wie die Befehlsliste per Referenz übergeben (müssen)
Muss das denn überhaupt eine dynamische Struktur sein? Schau was john-0 vorgeschlagen hat. Das wäre absolut in Ordnung.
Ich hatte zunächst angenommen, dass du da irgendwie eine Art mehrelementige globale Fehlervariable bauen wolltest (Tu das nicht!), weil mir sonst nicht klar war, wieso man sonst so etwas dynamisch bauen sollte. Aber anscheinend geht es ja um eine feste Liste von statischen Strings, und du bist bloß mit dem komplett falschen Datentyp unterwegs.
Wenn dir das von john-0 zu kompliziert ist, ginge auch ein Array von const char Zeigern auf die Fehlermeldungen. Aber du solltest dann dringend deine Einstellung zu modernem C++ überdenken:
Und was die weiteren Postings angeht (Lambda-Funktion)... ich glaube, ich will mein C++ von 1998 wiederhaben! Breymann, oder allenfalls noch Aupperle...
Klingt leider nach Fortschrittsverweigerung. Das neue Zeug ist ja nicht schwieriger oder unverständlicher als früher, du kennst es bloß nicht. Beziehungsweise, das neue Zeug macht klarer, was da wirklich passiert, wohingegen ein const-char-Array viele versteckte Fallstricke hätte, die dir wahrscheinlich gar nicht bewusst sind.
-
Sorry, ich habe meinen Beitrag editiert, das sollte nicht so unfreundlich klingen.
Vordefinierte Fehlermeldungsstrings könnte man vielleicht auch in einem Header definieren.
Jedenfalls wurde mir erst jetzt verständlich(er), wofür du das brauchst.
-
@Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:
O.k., dann werde ich das Fehlermeldungs-Vector-Array jedesmal genauso wie die Befehlsliste per Referenz übergeben (müssen) - sieht zwar plump aus, aber dürfte zumindest funktionieren! Und was die weiteren Postings angeht (Lambda-Funktion)... ich glaube, ich will mein C++ von 1998 wiederhaben! Breymann, oder allenfalls noch Aupperle...
Es gibt im Software Design der Grundsatz, dass man keine impliziten Abhängigkeiten von veränderlichen Objekten will. Daher arbeitet man lieber mit Dependency Injection, was nichts anderes als globale Variablen mit fancy Namen sind. Der Unterschied ist aber, dass die Abhängigkeit über das Interface der Funktion ersichtlich ist, während er bei bei globalen Variablen implizit erfolgt.
Im HPC gibt es einen sehr triftigen Grund für diese Vorgehen, globale Variablen versauen die Möglichkeit der Optimierung und kosten nicht unerheblich Performance. In Fortran gibt es daher das Kozept von „pure“ Funktions und Subroutines, die keinerlei globalen Kontext haben dürfen, d.h. der Compiler überwacht das strikt.