2016-12-12 3 views
2

J'ai un gros fichier de Constants.h fichier où environ 200 variables (principalement des tableaux) sont déclarées et initialisées. J'utilise un espace de noms.Trop de déclaration et d'initialisation dans le fichier d'en-tête C++

MÉTHODE 1:

//Constants.h 

#ifndef CONSTANTS_H_ 
#define CONSTANTS_H_ 

namespace LibConstants 
{ 
    const int a = 12; 
    const std::string theme[2]; = {"themeA", "themeB"}; 
    const int arr[2] = {1, 2}; 
    // and around 200 more declarations with initialization 
} 
#endif 

Ce fichier est .h#include dans presque tous les fichiers .cpp, mais chaque fois que sont utilisées seules variables très minimes comme LibConstants::theme[0].

Mes méthodes fonctionnent bien mais n'attribue-t-elle pas de mémoire inutilement? Dois-je suivre l'approche, pour définir uniquement les variables dans le fichier .h et initialiser dans .cpp?

Comme dans le code ci-dessous: MÉTHODE 2:

//Constants.h 

#ifndef CONSTANTS_H_ 
#define CONSTANTS_H_ 

namespace LibConstants { 

    std::string getMyTheme(int arg); 
    std::string getMyThemeName(int arg); 

    const int a; 
    const std::string theme[2]; 
    const int arr[2]; 
    // and around 200 more declarations with initialisation 
}; 
#endif 

dans le fichier Initialisation cpp

//Constants.cpp 

#include LibConstants.h 
using namespace LibConstants { 
    std::string getMyTheme(int arg) { 
     theme[2] = {"themeA", "themeB"}; 
     return theme[arg]; 
    } 
    std::string getMyThemeName(int arg) { 
     ... 
    } 
} 

En utilisant comme

//HelloWorld.cpp 

#include Constants.h 
int main() { 
    //METHOD 1: 
    std::string a = LibConstants::theme[0]; // arg=0 is dynamic and is being read from localStorage in my case. 
    //METHOD 2: 
    std::string a = LibConstants::getMyTheme(0); //Here also arg=0 is dynamic. 
    ... 
} 

Ici, l'allocation de mémoire inutile pour les variables inutiles ne se produira pas, sauf pour les tableaux qui sont déclarés comme const std::string st[2]; dans le fichier d'en-tête.

Ici, "arg = 0" est l'implication du temps d'exécution. Est-ce important si une variable ne dépend pas de l'exécution mais seulement de la compilation, auquel cas elle remplacera simplement la valeur de l'espace réservé dans le fichier .cpp correspondant?

Veuillez me corriger partout où je me trompe.

+0

Les constantes de temps de compilation vont au segment de données dans la plupart des implémentations, que vous les déclariez et que vous les initialisiez dans des fichiers d'en-tête ou de source. Par exemple, disons que vous avez 'int a [] = {/ * un grand tableau * /}'. 'a' n'est pas une constante mais son initialisation doit encore aller quelque part et le programme doit encore le charger. Donc, dans ce cas, je ne pense pas que cela fasse une différence matérielle. D'un autre côté, si une variable a besoin d'une exécution à l'initialisation, soit par le constructeur, soit par d'autres moyens. Il est préférable de l'intégrer dans une fonction et de la créer à la demande. –

+0

@YanZhou Merci pour la réponse rapide. Donc, vous voulez dire, les deux méthodes ci-dessus sont presque les mêmes parce que les deux sont compiler le temps et ne consomme pas de la mémoire, mais remplace seulement leurs espaces réservés dans chaque fichier .cpp? – myDoggyWritesCode

+0

Non. Donnez une minute pour composer une réponse. –

Répondre

2

Prenez l'exemple std::string. Tenir compte,

namespace Constants { 
const std::string str = "A not very short string"; 
} 

str est un type de classe, il a un constructeur, et il doit allouer de la mémoire pour stocker son contenu (sauf l'optimisation de chaîne courte est utilisée dans sa mise en œuvre. Même dans ce cas, il applique uniquement à, bien, "chaîne courte"). Il est déclaré une variable d'étendue d'espace de noms. Le programme doit donc construire cette variable au lancement. Chaque programme ayant cette variable déclarée devra allouer de la mémoire et initialiser son contenu. C'est un overhead que vous ne voulez probablement pas, en fonction de combien cela va affecter votre performance.

D'autre part, si vous avez,

const std::string &str() 
{ 
    const static std::string s = "A not very short string"; 

    return s; 
} 

Maintenant, vous avez une variable locale statique. Il sera initialisé à la première entrée de la fonction. Et il ne sera initialisé qu'une seule fois. Si str n'est jamais appelé, il ne sera pas initialisé du tout.

Cependant, notez que la chaîne littérale "A not very short string" va encore occuper de la mémoire. Où et comment est-ce que le magasin est défini. Habituellement dans les segments de données, et l'impact est généralement minime.

Contrairement aux types de classe. Il est préférable de définir des types fondamentaux, en particulier des types entiers dans l'en-tête.

Par exemple,

namespace Constants { 
constexpr int x = 10; 
} 

Un compilateur optimisé sera très probablement ne pas stocker la x variable et son contenu 10 du tout. Au lieu de cela, où x est utilisé, il sera remplacé par 10 et, dans certains cas, codé dans le code d'opération (appelé opérandes immédiates). Bien sûr, ceci est encore un détail d'implémentation. Et une telle optimisation ne peut pas être utilisée avec tous les compilateurs. Et si vous prenez l'adresse de x ou sinon ODR utilisé, le compilateur sera obligé de faire de la place pour cette variable quand même. Mais la ligne de fond est que, il sera très peu probable que vous serez pire en déclarant ces constantes dans l'en-tête que de le définir dans un fichier source externe.

+0

Pourquoi la définition de types entiers pour la déclaration de variables est-elle préférable? – myDoggyWritesCode

+0

S'il vous plaît voir si j'ai bien compris. En outre, cela expliquerait ce que j'ai écrit dans la dernière partie de ma question. Oui, un compilateur d'optimisation ne stockera pas la variable x et la valeur 10 car, dans ce cas, la participation à l'exécution n'est pas présente. Mais dans les cas où l'implication de l'exécution est là comme dans mon cas où je reçois l'argument du calcul logique/stockage local, il est bon de les faire passer par une fonction. Par fonction, je veux dire soit votre chemin const std :: string & str() ou le mien Méthode 2. Ai-je raison? Si, alors je suppose que suivre la méthode 2 est préférable car la plupart des variables de mon fichier ont besoin d'une logique d'exécution. – myDoggyWritesCode

+1

@ user3241111 Si vous stockez la variable intégrale dans un fichier source, il faudra non seulement un peu de stockage en mémoire, mais aussi empêcher le compilateur d'effectuer une optimisation. Par exemple, disons que l'intégrale est utilisée plus tard comme un nombre de boucles. Si le compilateur le voit dans l'en-tête, et le voit petit, il pourrait être capable de dérouler efficacement la boucle. Mais si vous le déclarez seulement, mais le définissez dans le fichier source, le compilateur ne pourra pas le faire. Pour votre deuxième commentaire, la réponse est oui. La clé est de se rappeler que les variables de portée globales et d'espaces de noms doivent être initialisées, qu'elles soient utilisées plus tard. –