Bonjour,
On a beau être pointu sur certains sujets, il est est d'autres qui résistent à notre manière d'appréhender les choses. Sur une grosse partie du futur standard, je n'ai aucun problème de compréhension. Mais sur les rvalue references, je cale très nettement.
Ceci étant dit, j'en viens à mon problème. A toutes fins utiles, voici une information d'importance :
Bien. J'essaie d'implémenter une surcouche à libxml2 qui corresponde à mes besoins. J'en viens au code de la classe xml::document :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 edt@desktop:~/ddcomp$ g++ -v Using built-in specs. Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
(nullptr, n'étant aps encore reconnu par g++ 4.4, est en fait un simple #define nullptr 0; ça n'a pas d'importance dans notre cas, mais ça peut en avoir si vous avez envie de compiler le code).
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 namespace xml { document&& read_xml_file(const std::string& path) { xmlDocPtr xmldoc = xmlReadFile(path.c_str(), NULL, 0); if (xmldoc) { return std::move(document(xmldoc)); } std::stringstream stream; stream << "cannot parse '" << path << "' as an XML file"; throw std::invalid_argument(stream.str()); } document::document(xmlDocPtr xmldoc) : m_doc(xmldoc) { } document::document(document&& other) : m_doc(other.m_doc) { other.m_doc = nullptr; } document::~document() { if (m_doc) { xmlFreeDoc(m_doc); } } }
Ce code est ainsi utilisé :
Dans mon esprit, les choses suivantes devraient se passer :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 { xml::document d = xml::read_xml_file(path_to_file); }
1) création d'une instance de xml::document()
2) transformation de cette instance en rvalue reference (grâce à std::move)
3) appel du move constructor, et donc échange des valeurs de pointeur xmlDocPtr (NULL contre un pointeur valide)
4) destruction de la rvalue reference, qui contient un nullptr (donc le destructeur ne fait pas grand chose)
5) destruction de l'instance "d"
C'est probablement là (dans mon esprit, je veux dire) que le bât blesse. Parce que les choses ne se passent pas du tout comme ça. A la place, le constructeur prenant une rvalue ref n'est jamais appelé, donc l'échange ne se passe jamais, et les deux instances existantes (la temporaire et celle qui est réellement utilisée) possèdent le même pointeur. Bien evidemement, un problème se pose lors de la destruction : xmlFreeDoc() plante, lamentablement, parce que le pointeur est libéré deux fois.
Ce n'est pas ce qui était prévu dans mon esprit torturé.
Est-ce que l'un de vous pourrait me pointer mon erreur - de raisonnement, de code, etc - et (bonus accordé sous la forme de mon éternelle gratitude) m'expliquer ce que visiblement, je n'ai pas compris (et comme je ne l'ai pas compris, je ne sais même pas ce que c'est) ?
Merci d'avance !
Partager