IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Problème de copie avec fstream


Sujet :

C++

  1. #21
    Membre confirmé
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2011
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Août 2011
    Messages : 88
    Par défaut
    Il est temps que je donne un peu plus d'informations, d'autant que j'ai dû affiner mon problème (merci koala).

    L'application qui doit utiliser le Logger est une application serveur, donc j'ai besoin de performances particulièrement rapides.
    Mais en parallèle, j'ai besoin de pouvoir consulter les logs en même temps que le serveur tourne, afin de ne pas avoir besoin de l'éteindre ou quoi que ce soit de ce genre pour pouvoir consulter des informations critiques.

    La particularité de mon Logger et de LogLevel, c'est que certains niveaux sont logués dans un fichier (et dossier) spécifique jour après jour, tandis que d'autres sont logués dans un unique fichier qui ne change pas.

    En plus de ça, j'affiche des informations directement dans la console pour lorsque je debug en direct avec le client.

    Cela veut dire que plusieurs niveaux peuvent avoir besoin d'un même fichier, ou pas.

    Donc il va falloir non pas que j'intègre l'ofstream directement dans LogLevel, mais plutôt que j'y mette une référence.

    @Ekleog > J'avais fait en sorte d'afficher quelque chose dans le destructeur de LogLevel, et à l'exécution je voyais bien que lorsque j'exécutais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    logger.register_level ("truc", LogLevel(/* ... */));
    Le destructeur était appelé, et par conséquent quand l'objet dans ma map était détruit à la sortie du scope, j'avais un crash car deux destructions d'ofstream sur le même fichier.

    Pour ce qui est des unique_ptr, je suis presque sûr de mal m'y prendre puisque ça ne marche pas mais que mon <bits/unique_ptr.h> contient bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // Assignment.
          unique_ptr&
          operator=(unique_ptr&& __u) noexcept
          {
    	reset(__u.release());
    	get_deleter() = std::forward<deleter_type>(__u.get_deleter());
    	return *this;
          }
     
          template<typename _Up, typename _Ep, typename = typename
    	std::enable_if
    	  <std::is_convertible<typename unique_ptr<_Up, _Ep>::pointer,
    			       pointer>::value
    	   && !std::is_array<_Up>::value>::type>
    	unique_ptr&
    	operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
    	{
    	  reset(__u.release());
    	  get_deleter() = std::forward<_Ep>(__u.get_deleter());
    	  return *this;
    	}
    J'ai essayé avec une petit structure ne contenant qu'un seul unique_ptr de le rentrer dans une map, mais je ne sais pas quel prototype donner à ma fonction pour que le move soit appelé (à chaque fois il me dit que j'ai pas de constructeur/operateur de copie parce que sinon il serait malformé ...).

  2. #22
    Membre émérite
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Par défaut
    koala01: OMG, je ne me souvenais plus que windows était aussi nul que ça ...
    Sinon, c'est vrai qu'un pimpl pourrait servir, mais pour le cas je pense qu'un flag de compilation suffirait -- pourquoi faire un indirection inutile, étant donné qu'après la compilation le comportement est fixé ?

    Nekkro:

    Si ton serveur tourne sous un linux, tout va bien avec le concept de garder le fichier ouvert.
    Si il toune sous windows, et que tu as beaucoup d'informations à logger, ça va être plus dur.
    Mais qui a un serveur sous windows ? (/me troll inside)

    Sinon, tu dis que pour utiliser plusieurs LogLevel avec le même fichier, il faudra mettre une référence, mais c'est plutôt un shared_ptr qu'il te faudrait ici.

    Sinon, logger.register_level ("truc", LogLevel(/* ... */)); va clairement déclencher le destructeur de LogLevel, mais pas à cause de la référence constante : c'est en fait à cause du LogLevel temporaire que tu créées, qui sera forcément détruit à la fin de l'instruction.
    Que voudrais-tu que ce code fasse d'autre ?

    Pour ce qui est des unique_ptr, je suis presque sûr de mal m'y prendre puisque ça ne marche pas mais que mon <bits/unique_ptr.h> contient bien :
    De toute façon, si tu arrives à instancier std::unique_ptr<un_type> ; c'est forcément qu'il a un move-ctor. Sinon, unique_ptr ne servirait à rien.
    Quand utilises-tu unique_ptr ? Penses-tu bien à utiliser std::move(ptr) ?

    Sinon, une struct de base rentrable dans une map (non testé) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    struct S {
       std::unique_ptr<int> p;
       S(std::unique_ptr<int> &&pp) : p(std::move(pp)) {} // Ctor a partir d'unique_ptr
       S(S &&o) : p(std::move(o.p)) {} // Move-ctor
       S & operator = (S && o) {
          p = std::move(o.p);
          return *this;
       }
    };
     
    // ...
    std::map<int, S> m;
    m.emplace(1, new int(42)); // Plus certain de la syntaxe d'emplace, a verifier
    m[2] = S(new int(1337));
    // Ou (pas sur) :
    m[2] = std::move(S(new int(1337)));

  3. #23
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    koala01: OMG, je ne me souvenais plus que windows était aussi nul que ça ...
    Pas nul, différent.

    Personnellement, étant plus habitué à windows, c'est le comportement de linux que je trouve rétrograde (plein d'opérations sans API qui obligent à exécuter des lignes de commandes et à parser les résultats, où à parser un fichier de config pour le modifier, pas de gestion de type comptage de référence pour les objets système (sémaphoe, mutex...)). Mais ce sont avant tout des choix de design et de philosophie.

    Et puis, sous windows, il est possible d'avoir un fichier ouvert par deux process en même temps (http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx, en particulier le paramètre sharemode), ce n'est juste pas le comportement par défaut (ce que je respecte, car dans le cas général, deux process qui accèdent au même fichier, c'est une corruption qui ne demande qu'à apparaître). Et donc ce n'est pas un comportement facilement utilisable avec les flux C++.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #24
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    koala01: OMG, je ne me souvenais plus que windows était aussi nul que ça ...
    Sinon, c'est vrai qu'un pimpl pourrait servir, mais pour le cas je pense qu'un flag de compilation suffirait -- pourquoi faire un indirection inutile, étant donné qu'après la compilation le comportement est fixé ?
    En fait, Nekkro m'a donné raison avec ses explications complémentaires (bon, d'accord, ce n'est qu'un hasard )

    En effet, en lisant ce qu'il doit faire, je me dis qu'il serait quand meme préférable qu'un Logger ne manipule qu'un seul fichier, et que l'on puisse en profiter pour gérer l'écriture (ou non) en fonction de la criticité...

    Bon, on s'écarte un peu du pimpl, mais, au final, on aurait quelque chose qui serait proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    enum LogLevel
    {
        ERROR_Critical, // ce qui provoque l'arret du service
        /* ... quelque niveau d'erreur non critiques */
        WARNING, // un avertissement
        /* éventuellement des niveau d'avertissement */
        INFO // juste une information
    }
    class Logger
    {
        public:
        static Logger &instance()
        {
             static Loger inst;
             return inst;
        }
        class Logger_impl
        {
            public:
                Logger_impl(std::string const & filename):filename_(filename){}
                virtual ~Logger_impl(){}
                virtual void write(std::string const &, LogLevel ) = 0;
        };
        void addLogger(Logger_impl * )
        {
            loggers_.push_back(logger);
        }
        void  write(std::string const & message, LogLevel level )
        {
     
            BOOST_FOREACH(Logger_impl * logger, loggers_)
           {
               logger->write(message, level);
           }
        }
        private:
        std::vector<Logger_impl *> loggers_;
     
        Logger(){}
        ~Logger()
        {
            BOOST_FOREACH(Logger_impl * logger, loggers_)
           {
               delete logger;
           }
        }
    };
    /* plusieurs classes héritant de Logger_impl pour les différentes 
     * politiques (en terme de gestion du fichier et en terme d'écriture
     * selon la criticité)
     */
     
    void log(std::string const & message, ErrorLevel level)
    {
         Logger::instance().write(message, level);
    }
    Je ne suis pas, par nature, très favorable à l'utilisation des singletons, mais, en l'occurrence, je me dis que, dans ce cas particulier, son utilisation peut se justifier

    On aurait, au début de l'application quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int init()
    {
     
        Logger::instance().addLogger(new LoggerErrorOnly("Path/To/error.log");
        Logger::instance().addLogger(new LoggerUsage("Path/To/use.log");
        /* pourquoi pas */
     
        Logger::instance().addLogger(new OutputToConsole();
        /* ... */
    }
    et, au niveau de l'utilisation de simples
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    log("le message de la mort qui tue", ERROR_Critical);
    /* ou */
    log("un autre message", WARNING);
    En prenant soin de séparer la classe Logger de la fonction log dans les fichiers d'en-tete (et surtout en implémentant les fonctions dans des fichiers d'implémentation et non inline comme je l'ai fait ici ), l'utilisation du Logger peut se faire de manière totalement transparente pour tout codeur qui ne va pas jeter un oeil à la fonction main

    De plus, comme on travaillerait sur avec des pointeurs sur loggers_impl (et que l'on a clairement déterminé qui s'occupe de les détruire ), il n'y aurait meme plus le problème d'une éventuelle tentative de copie du fichier, si celui-ci est ouvert au niveau des classes héritant de Logger_impl
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #25
    Membre confirmé
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2011
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Août 2011
    Messages : 88
    Par défaut
    Merci à tous pour vos conseils et critiques, j'ai finalement résolu mon problème en créant utilisant les unique_ptr<ofstream> que je créais dans Logger plutôt que dans LogLevel.

    Voici un petit sample final

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Logger logger;
    logger.register_level (LogLevel (LogPolicy::FILE_POLICY, "./logs/debug.log", Log::DEBUG));
    logger.target (Log::DEBUG) << "Un message de test.\n";
    logger.register_level (LogLevel (LogPolicy::FOLDER_POLICY, "./logs/debug/", Log::ALERT));
    logger.target (Log::ALERT) << "Un message de test.\n";

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. [AC-2003] problème de copie avec UPDATE
    Par yieiyiei dans le forum VBA Access
    Réponses: 3
    Dernier message: 31/03/2015, 13h25
  2. Problème de copie d'une base de données MySQL avec PHP
    Par rheem dans le forum SQL Procédural
    Réponses: 4
    Dernier message: 15/10/2007, 14h52
  3. problème de permissions avec fonction copy()
    Par jeanfrancois dans le forum Langage
    Réponses: 5
    Dernier message: 30/03/2006, 15h37
  4. Problème avec fstream
    Par cach dans le forum SL & STL
    Réponses: 17
    Dernier message: 27/02/2005, 12h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo