Loki foncteur – problème de mémoire

J’utilise Loki :: Functor dans mon projet pour un système d’événements simple. La fonction de gestionnaire de l’événement prend certains parameters. Dans ce cas, il s’appelle PrintEventSsortingng . Afin de le mettre en queue, les gestionnaires d’événements doivent avoir les mêmes prototypes – dans mon cas, void func(void) . Donc, CreateEvent prend le gestionnaire, crée un foncteur et lie le paramètre, ce qui donne un prototype void f (void) . Tout se passe bien (premier exemple avec chaîne stockée dans une variable locale), jusqu’à ce que je détruis la source de données avant d’appeler functor (deuxième exemple, chaîne créée temporairement). Voici le code:

 #include  #include  #include  #include "Loki/Functor.h" void PrintEventSsortingng(std::ssortingng str) { std::cout << "Test: " << str << std::endl; } Loki::Functor CreateEvent (std::ssortingng str) { Loki::Functor handler(PrintEventSsortingng); Loki::Functor event (Loki::BindFirst(handler, str)); return event; } int main (void) { std::ssortingng hello("hello"); Loki::Functor eventTestLocal(CreateEvent(hello)); eventTestLocal(); Loki::Functor eventTestTemp(CreateEvent("Hello world")); eventTestTemp(); return 0; } 

Ceci comstack, exécute, mais le second test ne fonctionne pas et valgrind génère beaucoup d’erreurs:

 == 30296 == Memcheck, un détecteur d’erreur de mémoire
 == 30296 == Copyright (C) 2002-2010 et GNU GPL'd, par Julian Seward et al.
 == 30296 == Utilisation de Valgrind-3.6.1 et de LibVEX;  relancez avec -h pour les informations de copyright
 == 30296 == Commande: ./main
 == 30296 == 
 Test: Bonjour tout le monde
 == 30296 == Lecture non valide de taille 4
 == 30296 == à l'adresse 0x40EB655: std :: chaîne_base, std :: allocator> :: chaîne_base (std :: ssortingng const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f2640 est de 8 octets à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 4
 == 30296 == à l'adresse 0x40EAD96: std :: ssortingng :: _ Rep :: _ M_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f263c est 4 octets à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 4
 == 30296 == à 0x40EADA5: std :: ssortingng :: _ Rep :: _ m_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f2638 est 0 octet à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 4
 == 30296 == à 0x40EADB3: std :: ssortingng :: _ Rep :: _ M_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f2638 est 0 octet à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 1
 == 30296 == à l'adresse 0x40294BA: memcpy (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40EADF7: std :: ssortingng :: _ Rep :: _ M_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x40EB68F: std :: chaîne_base, std :: allocator> :: chaîne_base (std :: ssortingng const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f264e est 22 octets à l'intérieur d'un bloc de taille 24 gratuit.
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 4
 == 30296 == à l'adresse 0x40294E8: memcpy (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40EADF7: std :: ssortingng :: _ Rep :: _ M_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x40EB68F: std :: chaîne_base, std :: allocator> :: chaîne_base (std :: ssortingng const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f2648 est de 16 octets à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (en dessous de main) (dans /lib/libc-2.14.so)
 == 30296 == 
 == 30296 == Lecture non valide de taille 4
 == 30296 == à 0x40EADF8: std :: ssortingng :: _ Rep :: _ M_clone (std :: allocator const &, unsigned int) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x40EB68F: std :: chaîne_base, std :: allocator> :: chaîne_base (std :: ssortingng const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x8049C4F: Loki :: Functor, Loki :: SingleThreaded> :: operator () (std :: ssortingng &) (Functor.h: 779)
 == 30296 == par 0x8049B59: Loki :: BinderFirst, Loki :: SingleThreaded>> :: operator () () (Functor.h: 908)
 == 30296 == par 0x80492D6: Loki :: Functor :: operator () () (Functor.h: 776)
 == 30296 == par 0x8048E7A: main (main.cpp: 26)
 == 30296 == L'adresse 0x42f2638 est 0 octet à l'intérieur d'un bloc de taille 24 free'd
 == 30296 == à l'adresse 0x4026B2C: suppression de l'opérateur (void *) (dans /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
 == 30296 == par 0x40E9C7A: std :: ssortingng :: _ Rep :: _ M_destroy (std :: allocator const &) (dans /usr/lib/libstdc++.so.6.0.16)
 == 30296 == par 0x41A0232: (sous la partie principale) (dans /lib/libc-2.14.so)

Je suspecte le foncteur de ne prendre qu’une référence à l’object passé, qui est ensuite détruit (tel que créé temporairement) et les problèmes commencent. Mais qu’est-ce que je fais mal ici? J’ai supposé que la reliure devait être utilisée pour stocker une partie de l’environnement (comme Andrei le décrit dans son livre), afin que l’environnement puisse être détruit.

Le problème est que l’object foncteur de Loki ne crée pas une copie conforme de la chaîne, mais stocke plutôt une référence à l’object chaîne que vous souhaitez lier à votre fonction. Cela est dû au fait que l’object foncteur de loki stocke un type de référence si le type de l’argument lié n’est pas un pointeur, un pointeur de membre ou un type arithmétique (c’est-à-dire un type avec lequel vous pouvez effectuer une opération arithmétique). Donc, comme la chaîne est temporaire et que seule une référence à la temporaire est stockée, une fois la stack retirée de l’appel de la fonction, l’access à la chaîne temporaire est perdu à partir de la référence interne dans l’object classeur et vous ne pouvez plus imprimer le fichier. chaîne.

Une solution possible pourrait être de créer votre fonction de manière à ce qu’elle utilise un type de pointeur intelligent pour pouvoir allouer un object de manière dynamic. La durée de vie de l’object s’étendra au-delà de la scope actuelle, tout en évitant les problèmes liés à la durée de vie aurait lieu avec un type de pointeur normal ou nu.

Edit : j’ai essayé cela … ne semble toujours pas fonctionner car il enregistre à nouveau une référence au type de pointeur intelligent, ce qui signifie que le pointeur est désalloué lorsque le pointeur intelligent temporaire sort de son périmètre. Alors oui, vous devrez soit modifier certaines définitions de la manière dont l’object functor de loki détermine si vous souhaitez stocker une référence ou une valeur, soit utiliser une autre version d’arguments de liaison pour les objects fonction tels que la version std::bind la nouvelle norme C ++ 11 std::bind et std::function