3

The following code works properly:

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <string>

using namespace boost::property_tree;

int main()
{
    ptree root;
    root.put("building.age", "42");
    root.put("company.age", "32");
    root.put("street.age", "19");

    ptree attached_node;
    attached_node.put("confirmed","yes");
    attached_node.put("approved","yes");

    for(auto it=root.begin();it!=root.end();++it)
    {
        std::cout
                << (it->first)
                << ": "
                << (it->second.get<std::string>("age"))
                << std::endl;
        if(it->first=="company")
            root.insert(it,make_pair("conditions",attached_node));
    }
    return 0;
}

However, once I iterate reversely via:

    for(auto it=root.rbegin();it!=root.rend();++it)

I face with an error:

 error: no matching function for call to ‘boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::insert(boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::reverse_iterator&, std::pair<const char*, boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >)’
     root.insert(it,make_pair("conditions",attached_node));
                                                         ^

How can I fix this problem?

ar2015
  • 4,338
  • 4
  • 36
  • 83

1 Answers1

4

That's because the insert function doesn't take a reverse iterator.

Use base() to get it:

enter image description here

root.insert(it.base(), make_pair("conditions",attached_node));

But BOOM: inifite loop! You're modifying while iterating. This is never rarely a good idea. Though iterator and reference stability prevent this from actually being Undefined Behaviour, in your case you happen to get keep finding the same company node "next" in the loop.

That's a preventable bug.

Don't be tempted to "just throw in a break; statement".

Fix it the mindful way: Use CQS.

Live On Coliru

auto it = find_by_key(root.rbegin(), root.rend(), "company");
if (it != root.rend())
    root.insert(it.base(), make_pair("conditions",attached_node));

See how much cleaner that became! find_by_key is a trivial wrapper around a standard algorithm:

template <typename It>
It find_by_key(It f, It l, std::string const& key) {
    return std::find_if(f, l, [&](auto const& pair) {
        //std::cout << pair.first << ": " << pair.second.get("age", "?") << "\n";
        return pair.first == key;
    });
}

If you can do without the debug possibility, it's more efficient to use the ptree interface:

Live On Coliru

auto it = root.equal_range("company").second;
if (it != root.not_found())
    root.insert(root.to_iterator(it), make_pair("conditions",attached_node));

In other words:

Algorithms, algorithms, algorithms.

For inspiration: "Never write a raw for loop" - Sean Parent

enter image description here

sehe
  • 328,274
  • 43
  • 416
  • 565