2010-04-30 6 views
0

Si j'ai un fichier d'en-tête foo.h et un fichier source foo.cpp et foo.cpp contient quelque chose le long des lignes de:Routine d'initialisation automatique dans la bibliothèque C++?

#ifdef WIN32 
class asdf { 
    asdf() { startup_code(); } 
    ~asdf() { cleanup_code(); } 
}; 
asdf __STARTUP_HANDLE__ 
#else 
//unix does not require startup or cleanup code in this case 
#endif 

mais foo.h ne définit pas asdf de classe, dire que j'ai un bar.cpp d'application:

#include "foo.h" 
//link in foo.lib, foo.dll, foo.so, etc 
int main() { 
    //do stuff 
    return 0; 
} 

Si bar.cpp est compilé sur une plate-forme WIN32, sera le asdf() et ~ asdf() soit appelée au moment opportun (avant main() et à la sortie du programme, respectivement) même si la classe asdf n'est pas définie dans foo.h, mais est liée à travers foo.cpp?

+3

Vous ne nommez pas sérieusement l'objet '__STARTUP_HANDLE__', n'est-ce pas? Tous les noms contenant un trait de soulignement double * ou * commençant par un trait de soulignement suivi d'une lettre majuscule sont réservés à l'implémentation. Le nom peut entrer en conflit avec un certain #define du compilateur ou objet défini par le moteur d'exécution. Jamais * jamais * utilisé des noms comme ça. – jalf

Répondre

5

Oui - mais soyez très prudent. L'ordre dans lequel les objets statiques (comme votre objet asdf) sont initialisés n'est pas défini. Il s'agit donc d'un comportement indéfini si un autre objet tente de référencer votre objet avant main(). En outre, __STARTUP_HANDLE__ n'est pas un identificateur valide. Les double-underscores ne sont pas autorisés dans les identifiants (même les macros), et un simple caractère de soulignement suivi d'une lettre majuscule n'est pas autorisé.

0

Tant que les objets (foo.o) sont eux-mêmes liés dans l'exécutable, cela fonctionnera (en supposant que l'ordre d'initialisation statique fiasco ne vous frappe pas). Cependant, si vous l'insérez dans une bibliothèque (foo.lib), ce ne sera pas le cas si vous ne marquez pas explicitement l'objet comme un "objet actif", mais je ne me souviens pas comment le faire dans MSVC.

0

sur Windows et avec DLL vous avez la possibilité d'utiliser la fonction DllMain qui sera appelée à la charge etc

BOOL WINAPI DllMain(HINSTANCE hinstDLL, 
        DWORD fdwReason, 
        LPVOID lpvReserved) { 

    switch (fdwReason) { 

    case DLL_PROCESS_ATTACH:  
    break; 

    case DLL_THREAD_ATTACH: 
    break; 

    case DLL_THREAD_DETACH: 
    break; 

    case DLL_PROCESS_DETACH: 
    break; 

    default: 
    break; 
    } 

    return TRUE; 
} 
+2

Pour compléter cela, sous Linux, vous pouvez étiqueter des fonctions * simples * qui ne prennent aucun argument comme ayant l'attribut 'constructor' ou' destructor'. L'éditeur de liens fait ensuite en sorte qu'ils soient appelés au démarrage du programme/chargement de la bibliothèque (ou sortie/déchargement) dans le cadre du mécanisme qui prend en charge les objets C++ avec ces durées de vie. –

1

Si ce n'est pas cassé, ne le répare pas. Attention à la question de l'ordre d'initialisation statique, comme le disent les autres réponses. Mais vous devriez vraiment corriger cet identifiant réservé. Fonctionne comme une bibliothèque d'exécution, et les bibliothèques d'exécution utilisent des noms de ce type, mais cela ne fait pas partie de la bibliothèque d'exécution, donc ce nom n'est pas autorisé.

#ifdef WIN32 
namespace { // anonymous namespace - no outside access 
class asdf { 
    asdf() { startup_code(); } 
    ~asdf() { cleanup_code(); } 
} x; // to create an instance 
} 
+0

Pourquoi n'avez-vous pas besoin de nommer la classe? Est-ce que le compilateur n'a pas besoin d'avoir un identifiant pour le type tel qu'il puisse décider du nom du constructeur/destructeur? –

+0

@Robert: désolé, c'était stupide avant. Oui, la classe doit avoir un nom pour avoir un constructeur: vP – Potatoswatter

Questions connexes