2

I am using boost 1.55.0 on ubuntu 12.04lts with clang 3.4.

I have a boost::property_tree::ptree whose xml input looks like:

<root>
    <persons>
        <person>
            <name>dad</name>
            <age>43</age>
        </person>
        <person>
            <name>me</name>
            <age>4</age>
        </person>
    </persons>
</root>

So I have a list of nodes with the same tag.

To read them I iterate over the tree, and depending on a condition I want to erase a node. This looks like:

boost::property_tree::ptree pt;
boost::property_tree::read_xml(inputFileName, pt);

boost::property_tree::ptree& persons = pt.get_child("root");
for(boost::property_tree::ptree::const_iterator it = persons.begin(); it != persons.end(); ++it)
{
    std::string name = it->second.get<std::string>("name");
    if(name == "dad")
        // erase that name node from pt
        persons.erase(it->second.find("name"); // this doesn't work
}

[Edit]As the answer from pmr supposes, I wrote the following code:

boost::property_tree::ptree::iterator i = persons.begin();
auto assoc_i = it->second.find("name");
auto ci = persons.to_iterator(assoc_i);
std::advance(i, std::distance<boost::property_tree::ptree::const_iterator>(iterator, ci)); // --> here it hangs
persons.erase(i);

Now it compiles, and the application does not crash, but it hangs at the mentioned position. And I don't know why. [/Edit]

Many thanks in advance.

Rico-E
  • 1,806
  • 2
  • 28
  • 47

2 Answers2

4

C++11 APIs for containers specify a member function iterator container::erase(const_iterator, const_iterator). Unfortunately, basic_ptree does not do that, so you are stuck with old C++ way of converting a const_iterator to an iterator:

// tree is your ptree, my_const_iter a ptree::const_iterator
ptree::iterator i = tree.begin();
advance (i, std::distance<ConstIter>(i,my_const_iter));
pmr
  • 58,701
  • 10
  • 113
  • 156
  • @DieterLücking See signature 2 here: http://en.cppreference.com/w/cpp/container/vector/erase – pmr Jan 29 '14 at 10:25
  • thank you. But now I have another problem. I explained it in an edit of my question. Do you know, why the application hangs now? – Rico-E Jan 29 '14 at 10:53
  • 1
    @Rico-E I really recommend keeping to one topic per question. It is hard to see what is begin asked now. You might also want to split the sub-operations of the statement to get the exact point where the program hangs and look at it in a debugger. – pmr Jan 29 '14 at 11:01
  • @pmr Thank you. I deleted all other questions, and splitted the code into sub-operations (edited my post). And the std::advance still does not work. Since I am using clang, I don't have a debugger. Or is there a clang debugger? – Rico-E Jan 29 '14 at 13:34
  • You can use GDB (preferably 7+) or LLDB (since 6.3 ships with Xcode). I'm not sure why you'd think a compiler toolchain as widely used as clang wouldn't support the same tools for debugging as you'd expect. It even now supports limited integration with Visual Studio on Windows. Quite impressive, really. – Louis St-Amour Jan 29 '14 at 14:01
  • See also: http://stackoverflow.com/questions/21132194/is-it-possible-to-debug-a-gcc-compiled-program-using-lldb-or-debug-a-clang-comp – Louis St-Amour Jan 29 '14 at 14:05
  • @LouisSt-Amour: I am sorry, but according to [this link](http://lldb.llvm.org/download.html) it seems to me, that there is no stable version of lldb. Or could you provide another link where I can find a stable version of lldb – Rico-E Jan 31 '14 at 13:39
  • The homepage states: Note that LLDB generally builds from top-of-trunk on Mac OS X with Xcode and on Linux (with clang and libstdc++/libc++). – Louis St-Amour Jan 31 '14 at 18:11
  • It also says: LLDB is the default debugger in Xcode on Mac OS X and supports debugging C, Objective-C and C++ on the desktop and iOS devices and simulator. – Louis St-Amour Jan 31 '14 at 18:11
4

Your issue at hand has little to do with the constness of the iterators, you are simply erasing with the wrong ptree iterator.

ptree& persons = pt.get_child("root.persons");
for(auto it = persons.begin(); it != persons.end();) {
   if(it->second.get<string>("name") == "dad")
        it = persons.erase(it);
    else
        ++it;
}

The ptree uses a multi_index for sub-nodes, and to keep an iteration stable over erasures, you must use the iterator returned from the erase() operation to continue the iteration, a common pattern.

Note that the XML in the question has an / (</age>) termination missing, it wouldn't validate. I am not editing the question to fix it since this could be one of the problems that you experience with the execution of the program.

Output of processing the ptree with the above code via write_xml(std::out, pt):

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <persons>
    <person>
      <name>me</name>
      <age>4</age>
    </person>
  </persons>
</root>
mockinterface
  • 14,452
  • 5
  • 28
  • 49