2013-07-21 2 views
1

J'ai utilisé un modèle dans une bibliothèque que je crée qui utilise passe un nom String d'un objet au constructeur de son objet de base. J'ai essayé d'utiliser les chaînes std :: string et c-style, mais je continue d'avoir des erreurs de mémoire bizarres avec Valgrind.Attribution de chaîne de temps de compilation pour l'identification d'exécution

class Base { 
public: 
    Base(std::string name) : name(name) {} 
    virtual ~Base() {} 
    std::string getName() { return name; } 
private: 
    std::string name; 
}; 

class Derived : public Base { 
public: 
    Derived() : Base("Derived") {} 
}; 

int main() { 
    Base* derived = new Derived; 
    std::cout << derived->getName() << "\n"; 
    delete derived; 
} 

(Ceci compile et fonctionne très bien dans Valgrind)

Est-ce quelque chose comme ce coffre-fort? J'utilise 'const char *' au lieu de 'std :: string' en ce moment, est-ce que c'est sûr?

Existe-t-il une alternative plus sûre, de préférence sans utiliser de virtual? Edit: Y a-t-il un moyen de faire cela avec des templates? Je ne veux pas utiliser RTTI car le nom est tronqué et je veux que le nom soit 'normal' pour être utilisé avec les scripts/persistance des données.

+0

Votre classe de base a besoin d'un destructeur virtuel (c'est probablement la cause des erreurs que vous voyez). En outre, vous devriez probablement utiliser 'unique_ptr' ou' shared_ptr' au lieu de pointeurs bruts. – syam

+0

Juste vérifié, toutes les bases sont virtuelles dans mon code. – h4tch

+0

Pour les constantes littérales de chaîne, n'utilisez pas un pointeur intelligent a la 'std :: unique_ptr (" hello ")' car le 'char const *' pointe sur le stockage de données statique, pas sur le tas. Et je ne vois pas la question ici, ce code est sûr et bien mais apparemment ne représente pas la partie problématique. – Potatoswatter

Répondre

0

Tout ce que vous faites ici est bon.

Les modèles ne vous apporteraient rien parce que vous avez toujours besoin de stocker un pointeur d'exécution dans la classe de base pour l'identification dynamique.

Les pointeurs intelligents ne vous rapporteront rien car la durée de vie de la chaîne correspond au programme entier. Si vous ne calculez rien, char const * et l'initialisation à partir d'un littéral de chaîne sont idéales. Si vous calculez la chaîne, vous pouvez utiliser static std::string const enveloppé dans une fonction getter.

class Derived : public Base { 
public: 
    Derived() : Base(get_name()) {} 
private: 
    static std::string const & get_name() { 
     static std::string const name = "Derived"; // or = compute_name(); 
     return name; 
    } 
}; 

Cela évite l'ordre d'initialisation statique fiasco. (La fonction getter reçoit une protection supplémentaire de multithreading du compilateur.) La durée de vie du string correspond à la durée de vie du programme. Le Base peut stocker un string const & ou un char const *, cela n'a pas vraiment d'importance. Je recommande char const * parce que la référence string pourrait potentiellement être accidentellement initialisée avec un temporaire.

+0

L'acheteur méfiez-vous: Visual C++ n'implémente pas l'initialisation thread-safe des fonctions statiques locales. – Casey

+0

@Casey Etes-vous sûr? Ce n'est pas une fonctionnalité compliquée. – Potatoswatter

+0

Très sûr. [Voici une question à propos de VS2010.] (Http://stackoverflow.com/questions/10585928/is-static-init-thread-safe-with-vc2010) J'ai personnellement fait des recherches sur VS2012. Apparemment, il est [prévu pour "la libération post-2013"] (https://udta1g.blu.livefilestore.com/y2pMXBJL7l2a5UOf_pXnLXghSUhPWK8w5skFyc50SVFcMjVwa1guQnM6R0NNLN1buBUNPGbLBejpYXXBXSbqshQKKWVfQxvJjk2jGRPPbL-UBu7gaao4RxifZgPXY5ksdei/image1.png?psid=1). – Casey

Questions connexes