3

Ich habe ein seltsames Verhalten auf VS2010 Teil erlebt.Haltepunkt nicht in einer globalen statischen initialisierten Klasse in einer statisch verknüpften Lib getroffen

Ich habe diesen einfachen Code zu zwei CPP-Dateien hinzugefügt, und legte einen Haltepunkt in der angegebenen Codezeile

 
namespace { 
    class TestClass 
    { 
    public: 
     TestClass() 
     { 
     printf("");  // ### BREAKPOINT_HERE 
     } 
    }; 
} 
TestClass a; 

Das Seltsame ist, dass, sobald das Programm kompiliert und ausgeführt, Breakpoint in einer der Dateien ist korrekt, und in der anderen wird automatisch mit einer Warnung deaktiviert: 'Der Haltepunkt wird derzeit nicht getroffen. Für dieses Dokument wurden keine Symbole geladen.

Beide CPP-Dateien wurden auf die gleiche Weise erstellt und haben die gleichen Eigenschaften. Das Projekt, in dem sie sich befinden, hat eine erhebliche Anzahl von Dateien, aber die Datei, mit der ich ein Problem hatte, wurde zuletzt nicht hinzugefügt - es gibt neuere Dateien, die das Problem nicht aufweisen.

Kann mir jemand sagen, was das Problem sein kann?

Cheers, Paksas

+1

ist es möglich, dass Sie versuchen, denselben Typ zweimal zu registrieren? – ybungalobill

+0

Bitte zeigen Sie den Code aus beiden Dateien an. – Suma

+0

Versuchen Sie, die Lösung neu zu erstellen - dieser Fehler zeigt an, dass Ihre Debugging-Symbole für die aktuelle Datei nicht gültig sind. Eine Neuerstellung sollte die Debugging-Symbole neu generieren. –

Antwort

1

Ich denke, das Problem ist nicht mit dem Compiler, sondern mit dem Linker. Wenn in einem Modul in einer Bibliothek keine expliziten Zugriffe auf ein Symbol angezeigt werden, wird das Modul nicht verknüpft. Daher werden statische Objekte in diesem Modul niemals existieren.

Um zu verstehen, warum das so ist, denken Sie zurück an eine Zeit vor C++. Der Zweck einer Bibliothek war es, alle Funktionen, die Sie benötigen, in eine einzige Datei zu packen. Der Linker würde jedes Modul in der Bibliothek durchlaufen, wobei ein Modul durch Kompilieren einer einzelnen Quelldatei definiert wird. Wenn das Programm ein im Modul definiertes Symbol benötigt, wird dieses Modul verknüpft. Wenn nicht, würde es übersprungen werden, so dass nicht verwendete Teile der Bibliothek die Anwendung nicht aufblähen.

Dieser Prozess ist rekursiv. Wenn also Modul A etwas von Modul B erfordert, wird Modul B verknüpft, auch wenn das Programm es nicht direkt benötigt. Das ist der Schlüssel zum Umgehen des Problems - stellen Sie sicher, dass das Hauptmodul Ihrer Bibliothek auf mindestens ein Objekt oder eine Funktion von jedem Modul zugreift, das Ihre statischen Initialisierer enthält.

+0

Andere statische Objekte aus dem Modul durchkommen - es gibt nur ein paar Dateien, die das Problem verursachen –

+0

Siehe auch http://stackoverflow.com/questions/4383602/ Wie-zu-Kraft-Einbeziehung-von-unbenutzten-Objekt-Definitionen-in-einer-Bibliothek - dies erklärt technische Probleme ziemlich gut. – Suma

+0

@Paksas, was ich vorschlage ist, dass entweder alle oder keine der Objekte in einer Datei verknüpft werden. Siehst du das? –

0

nutzte die Tatsache, dass statische Objekte vor den Haupt initialisiert get() genannt wird

zu füllen Ich glaube, Sie die Tatsache fehlen, dass Compiler darf die dynamische Initialisierung von nicht lokalen Variablen mit statischer Speicherdauer bis zu ihrer ersten Verwendung verzögern. Wenn der Code diese Registrierungsklassen nie verwendet, erstellt der Compiler keinen Code für die dynamische Initialisierung.

+2

Entschuldigung, Sie irren sich "Wenn eine Variable mit statischer Speicherdauer eine Initialisierung oder einen Destruktor mit Nebeneffekten hat, wird sie nicht eliminiert, auch wenn sie unbenutzt erscheint", verwirren Sie die Statiken, die lokal für Funktionen sind . – ybungalobill

+0

Sie haben Recht, der Standard hat diese Formulierung, und es wurde in einem sehr langen Thread vorher debattiert: http://www.velocityreviews.com/forums/t720839-initialization-of-unused-global-variables-from-static -libraries.html Jetzt, ob ein Fehler oder nicht, initialisiert VC nicht verwendete Objekte mit statischer Speicherdauer nicht dynamisch. –

1

Ich habe schon früher ein ähnliches Problem gehabt, obwohl ich dann den Registrierungscode in einem separaten LIB-Projekt definiert hatte. Es stellt sich heraus, dass der Linker meine Objekte wegoptimiert! Meine Lösung bestand darin, diese "Registrierungsobjekte" in einer Funktion zu referenzieren. Ich habe dann die Funktion aus meiner Anwendung aufgerufen. Vielleicht passiert so etwas hier? Versuchen Sie, die gesamte Programmoptimierung auszuschalten und sehen Sie, was passiert. Möglicherweise müssen Sie etwas tun, damit das Optimierungsprogramm diese Objekte nicht als toten Code behandelt. (Ich wünschte, Visual C++ Attribute als nicht tot zur Kennzeichnung Code hatte ...)

Update: Kurz der eine saubere Art und Weise zu finden, Gegenstände als nicht tot Markierung, hatte ich den Code in beiden Projekten zu berühren. Im LIB-Projekt habe ich Funktionen definiert und keine globalen Objekte. Im App-Projekt habe ich Funktionen definiert, die diese Funktionen aufrufen.

Was können Sie tun, ist dies:

// Registrations.cpp 
#ifdef EXPORT_REGISTRATIONS 
#define REGISTRATION_CODE(theClass) \ 
     void register_##theClass##_function() { \ 
      // Code for registering your class \ 
     } 
#else 
#define REGISTRATION_CODE(theClass) \ 
     // Declare a function prototype for the function in LIB \ 
     void register_##theClass##_function(); \ 
     struct theClass##importer { \ 
      theClass##importer() { \ 
       // Call into LIB \ 
       register_##theClass##_function(); \ 
      } \ 
     } g_##theClass##importerInstance; \ 
#endif 

REGISTRATION_CODE(MyClass); 
REGISTRATION_CODE(MyOtherClass); 

Dann im LIB-Projekt, stellen Sie sicher, EXPORT_REGISTRATIONS definiert ist. Dadurch werden die Funktionen generiert, die die tatsächliche Registrierung ausführen, die Sie durchführen möchten. Stellen Sie im App-Projekt sicher, dass EXPORT_REGISTRATIONSnicht definiert ist. #include "<path to lib project>\Registrations.cpp" im App-Projekt. Dadurch werden globale Objekte (wie Ihre ursprünglichen) generiert, die die im LIB-Projekt definierten Funktionen aufrufen.

So habe ich mein Problem gelöst. Ihre Laufleistung kann variieren. :)

+0

Wie kann der Compiler ein statisches Objekt optimieren, wenn es nicht weiß, ob eine andere Übersetzungseinheit versucht, es zu verwenden? Der Linker, auf der anderen Seite ... –

+0

Ich meinte den Linker ... –

+0

Ich habe alle Optimierungen - von den Bibliotheken und von der App (sowohl Kompilieren und Link-bezogenen) - es hat nicht geholfen. Wenn es Linker Optimierungen Fehler war - das sollte helfen, oder? –

0

Bitte, fallen Sie alles andere, was Sie tun und read this now. (Lesen Sie auch den folgenden Abschnitt, 10.15.)

Zweitens, wenn Sie zufällig nicht in dieses spezielle Problem fallen, können Sie bitte die Definition für getClassesRegistry zeigen? Und haben Sie dort einen Haltepunkt gesetzt oder eine andere Diagnose verwendet, um zu verifizieren, dass diese Methode wirklich nicht aufgerufen wird?

-1

Ich habe einige neue Fakten gefunden, die die Situation beleuchten und die Hauptbotschaft editieren können.

Versuchen Sie, die gesamte Programmoptimierung auszuschalten und sehen Sie, was passiert. Möglicherweise müssen Sie etwas tun, damit das Optimierungsprogramm diese Objekte nicht als toten Code behandelt.

Die gesamte Lösung wird im Debug-Modus kompiliert, wobei alle Optimierungen deaktiviert sind. Das Projekt, in dem sich die Dateien befinden, wird als statische Bibliothek kompiliert.

+0

Bitte verwenden Sie Kommentare zu Antworten. Das Posten von Kommentaren als Antworten ist eine schnelle Möglichkeit, negative Antworten zu erhalten. –

+1

mein Schlechter - das ist mein erster Beitrag hier und ich bin nicht vertraut mit den Zoll :) wird compy –

+1

Se meine Antwort unten für ein Update auf, wie Sie dies lösen können. –

1

Sie haben das Objekt a in zwei verschiedenen Dateien definiert. Sie haben die One-Definition-Regel verletzt, und der Compiler kann in dieser Situation frei machen, was er will.

Geben Sie einer Ihrer Variablen einen anderen Namen, und Sie sollten in der Lage sein zu beobachten, dass beide initialisiert werden.

(Die verschiedenen Definitionen von TestClass sind aus zwei Gründen in Ordnung. Eine ist, dass sie sich in separaten Namespaces befinden und die andere, selbst wenn sie nicht in separaten Namespaces wären, wären ihre Definitionen identisch und die eine -Definition Regel macht eine Ausnahme dafür.)

+0

Bevor die Frage bearbeitet wurde, waren die globalen statischen Objekte ebenfalls Teil des Namensraums. –

+0

Vielleicht @Mark, aber vielleicht nicht. Möglicherweise wurde das Makro in zwei Klassen mit demselben Namen aufgerufen, wodurch das Makro sie im selben Namespace definierte. –

+0

Ich habe getan, was Sie empfohlen - nichts geändert ... –

Verwandte Themen