Boost.PropertyTree crash when iterating over some empty trees - c++

Looping over the children of an empty Boost.PropertyTree is usually a no-op:
ptree empty;
for (auto const& elements : empty)
{
std::cout << "child\n"; // Executed 0 times, as expected
}
but sometimes it crashes with an access violation :
ptree empty;
for (auto const& elements : empty.get_child("non-existent", ptree{})))
{
std::cout << "child\n";
}
Access violation reading location 0xFFFFFFFFFFFFFFFF.
(Inside basic_ptree<K, D, C>::begin() const)
Now obviously empty has no child "non-existent", but there's a default value provided (ptree{}). We know from the first example that it's OK to loop over an empty collection.
The usual way to detect a read failure does not work as this is an Access Violation / Undefined Behavior inside Boost.PropertyTree.
How can you distinguish between the first and second type of empty property trees, so you can avoid iterating over the type that blows up?

The problem is that Boost.PropertyTree takes that default (a temporary) by const reference. And the temporary dies immediately, even before begin is called on it.
You can't detect this problem at runtime. The workaround is to have a non-temporary empty ptree to use as a default. This can be a const ptree so you can share it between different calls. Another solution is to use this trick.

Related

What exactly is causing my node class with a vector housing the pointers of the class to cause segmentation faults?

Currently I'm just starting off with creating nodes for my tree. The idea I had in mind was to simply create something like this:
class Node
{
private:
int key_;
std::vector< Node * > child_;
public:
Node(int key)
: key_(key), child_()
{
}
Node * get_child(int key) const
{
return child_[key];
}
};
Nothing too fancy, right?
Inside the main, I call all the header files and have initialized the whole entire thing like this
Node child(0);
What causes some frustration right now is when I try to simply just check if everything in my node is truly initialized. All I'm doing in the main is this.
std::cout << node.get_child(0) << std::endl;
The dreaded segmentation fault error comes up which means that the memory allocation of the vector is off. My question is this, if this is actually what's happening, what in my code is wrong so far? If it is not, please clarify on what exactly in my class template is wrong.
In the constructor for Node, you set the internal key value, and construct an empty vector. You don't have any code shown that adds anything to the vector, and trying to access element 0 of an empty vector results in Undefined Behavior (a crash, in your case).
You probably want something like child(1) (to create one node in the vector), child(key + 1, nullptr) (to create null node pointers so that elements in the 0..k inclusive range are valid) or a loop in the constructor to set actual nodes into the vector.

remove element from std::list by reference

std::list<Reader> readers;
readers.push_back(Reader());
Reader& r = *(readers.begin());
/* at this point, the exact place in list, where the reader was picked out, is forgotten.
Only 'r' shows which element of the list it is. */
readers.erase(r); //<---how to do this?
Clients get the new instances 'reader' objects from a manager/dispatcher. The manager maintains an internal list of whatever was dispatched and invalidates/frees up a cached data if "everyone interested" picked it up by observing the pool of readers dispatched.
When the client is no longer interested in the data, it should return the reader to the manager for removal from the pool. But I don't want the client to keep an iterator - it's absolutely uninterested in guts of the manager and the pool of the readers; only needs this one own reader it got, not an iterator pointing to it. So, for deletion, it calls the manager's cleanup function, with the reference to that single reader.
Is there a nicer way to erase that reader from the list than to iterate through the whole list in search of that one reader the reference leads to?
you can compare the pointers to check if they are same object
readers.remove_if([r=&r](auto& x){return &x==r;});
Your options if you only have a reference to the object is to use std::list::remove
readers.remove(r);
or std::find in conjunction with std::list::erase
readers.erase(std::find(readers.begin(), readers.end(), r));
The former has to iterate the entire list while the latter will stop when it finds the first element and then removes it. For large list this can make a big difference.
Both of these options only work when the items are unique. If you have non unique elements then you can use std::find_if and provide a functor that compares the address of the items. That way you can guarantee you only delete the object the reference actually refers to instead of compares equal to.
readers.erase(std::find_if(readers.begin(), readers.end(), [&](const auto& e) {return &r == &e;}));
Use std::remove in combination with erase
readers.erase(std::remove(readers.begin(), readers.end(), r), readers.end());
Also, u can't delete element from list by value, without iterating it. If you think about it, it doesn't even make sense, because pointers inside the list have to be updated.
If the list can contain equal values then you can do something like the following
#include <iostream>
#include <list>
int main()
{
struct Reader { std::pair<char, int> p; };
std::list<Reader> readers;
readers.push_back({{ 'A', 1 } });
readers.push_back({ { 'A', 2 } });
Reader &rr = readers.back();
readers.push_back({ { 'A', 3 } });
readers.remove_if([&rr](const Reader &r) { return &r == &rr; });
for (const auto &r : readers)
{
std::cout << r.p.first << ' ' << r.p.second << std::endl;
}
return 0;
}
The program output is
A 1
A 3

Set iterator invalidated by move semantic

I have the following immutable container class (public access to values is just for reasons of simplicity):
struct Container
{
std::unordered_set<int> values;
//Default constructor
Container() = default;
//Copy constructor
Container(const Container& other)
: values(other.values)
{ }
//Move constructor
Container(const Container&& other)
: values(std::move(other.values))
{ }
Container RemoveValue(int value) const
{
//Create a copy of this object
Container copy(*this);
//Remove one element from the copy
copy.values.erase(value);
return copy;
}
};
This container contains a set of values. The method RemoveValue() returns a copy of the current object where a specific value has been removed. An appropriate move constructor is defined for this struct.
I use this container as follows:
int main()
{
std::vector<Container> containers;
{
//Initialization
Container initialContainer;
initialContainer.values.insert(1);
initialContainer.values.insert(2);
containers.push_back(std::move(initialContainer));
}
const Container* currentContainer = &containers.front();
for (int value : currentContainer->values)
{
Container newContainer = currentContainer->RemoveValue(value);
//Do some checks, then...
containers.push_back(std::move(newContainer));
}
std::cout << containers.size() << std::endl;
return 0;
}
I initialize a vector of containers with a single container (with values 1 and 2). Then, I acquire a pointer to this initial element and iterate every value. For each value, I call RemoveValue() and insert the resulting container into the vector.
In gcc, this seems to work just fine. However, I get runtime errors in Visual Studio 2015.
In Debug Mode, the error is: "list iterator not incrementable". This error occurs after the first iteration at for (int value : currentContainer->values) (when the iterator is to be incremented).
In Release Mode, the error is: "Access violation reading at position 0x38". This error occurs at copy.values.erase(value) in RemoveValue. But only in the second iteration. Surprisingly, values does not contain elements at this point, anymore (size() returns 0).
I don't understand either of these errors. How can I resolve them?
A C++ Shell example also runs without errors. However, it outputs 2 as the final number of containers, whereas I expected three (the initial one, one with 1 removed, one with 2 removed).
currentContainer is a pointer to an element of the vector containers. The loop body modifies containers by calling push_back. That can invalidate pointers into the vector, and if it does, currentContainer can end up pointing to garbage.
In general, don't use pointers to objects that are held in an std::vector. Instead, use containers.front() or containers[0] to get at the first element.

C++ Marking objects for removal in STD list via nullptrs

I was wondering if this is an accaptable practice:
struct Item { };
std::list<std::shared_ptr<Item>> Items;
std::list<std::shared_ptr<Item>> RemovedItems;
void Update()
{
Items.push_back(std::make_shared<Item>()); // sample item
for (auto ItemIterator=Items.begin();ItemIterator!=Items.end();ItemIterator++)
{
if (true) { // a complex condition, (true) is for demo purposes
RemovedItems.push_back(std::move(*ItemIterator)); // move ownership
*ItemIterator=nullptr; // set current item to nullptr
}
// One of the downsides, is that we have to always check if
// the current iterator value is not a nullptr
if (*ItemIterator!=nullptr) {
// A complex loop where Items collection could be modified
}
}
// After the loop is done, we can now safely remove our objects
RemovedItems.clear(); // calls destructors on objects
//finally clear the items that are nullptr
Items.erase( std::remove_if( Items.begin(), Items.end(),
[](const std::shared_ptr<Item>& ItemToCheck){
return ItemToCheck==nullptr;
}), Items.end() );
}
The idea here is that we're marking Items container could be effected by outside sources. When an item is removed from the container, it's simply set to nullptr but moved to RemovedItems before that.
Something like an event might effect the Items and add/remove items, so I had to come up with this solution.
Does this seem like a good idea?
I think you are complicating things too much. If you are a in multi-threaded situation (you didn't mention it in your question), you would certainly need some locks guarding reads from other threads that access your modified lists. Since there are no concurrent data structures in the Standard Library, you would need to add such stuff yourself.
For single-threaded code, you can simply call the std:list member remove_if with your predicate. There is no need to set pointers to null, store them and do multiple passes over your data.
#include <algorithm>
#include <list>
#include <memory>
#include <iostream>
using Item = int;
int main()
{
auto lst = std::list< std::shared_ptr<Item> >
{
std::make_shared<int>(0),
std::make_shared<int>(1),
std::make_shared<int>(2),
std::make_shared<int>(3),
};
// shared_ptrs to even elements
auto x0 = *std::next(begin(lst), 0);
auto x2 = *std::next(begin(lst), 2);
// erase even numbers
lst.remove_if([](std::shared_ptr<int> p){
return *p % 2 == 0;
});
// even numbers have been erased
for (auto it = begin(lst); it != end(lst); ++it)
std::cout << **it << ",";
std::cout << "\n";
// shared pointers to even members are still valid
std::cout << *x0 << "," << *x2;
}
Live Example.
Note that the elements have been really erased from the list, not just put at the end of the list. The latter effect is what the standard algorithm std::remove_if would do, and after which you would have to call the std::list member function erase. This two-step erase-remove idiom looks like this
// move even numbers to the end of the list in an unspecified state
auto res = std::remove_if(begin(lst), end(lst), [](std::shared_ptr<int> p){
return *p % 2 == 0;
});
// erase even numbers
lst.erase(res, end(lst));
Live Example.
However, in both cases, the underlying Item elements have not been deleted, since they each still have a shared pointer associated to them. Only if the refence counts would drop to zero, would those former list elements actually be deleted.
If I was reviewing this code I would say it's not acceptable.
What is the purpose of the two-stage removal? An unusual decision like that needs comments explaining its purpose. Despite repeated requests you have failed to explain the point of it.
The idea here is that we're marking Items container could be effected by outside sources.
Do you mean "The idea here is that while we're marking Items container could be effected by outside sources." ? Otherwise that sentence doesn't make sense.
How could it be affected? Your explanation isn't clear:
Think of a Root -> Parent -> Child relationship. An event might trigger in a Child that could remove Parent from Root. So the loop might break in the middle and iterator will be invalid.
That doesn't explain anything, it's far too vague, using very broad terms. Explain what you mean.
A "parent-child relationship" could mean lots of different things. Do you mean the types are related, by inheritance? Objects are related, by ownership? What?
What kind of "event"? Event can mean lots of things, I wish people on StackOverflow would stop using the word "event" to mean specific things and assuming everyone else knows what meaning they intend. Do you mean an asynchronous event, e.g. in another thread? Or do you mean destroying an Item could cause the removal of other elements from the Items list?
If you mean an asynchronous event, your solution completely fails to address the problem. You cannot safely iterate over any standard container if that container can be modidifed at the same time. To make that safe you must do something (e.g. lock a mutex) to ensure exclusive access to the container while modifying it.
Based on this comment:
// A complex loop where Items collection could be modified
I assume you don't mean an asynchronous event (but then why do you say "outside sources" could alter the container) in which case your solution does ensure that iterators remain valid while the "complex loop" iterates over the list, but why do need the actual Item objects to remain valid, rather than just keeping iterators valid? Couldn't you just set the element to nullptr without putting it in RemovedItems, then do Items.remove_if([](shared_ptr<Item> const& p) { return !p; } at the end? You need to explain a bit more about what your "complex loop" can do to the container or to the items.
Why is RemovedItems not a local variable in the Update() function? It doesn't seem to be needed outside that function. Why not use the new C++11 range-based for loop to iterate over the list?
Finally, why is everything named with a capital letter?! Naming local variables and functions with a capital letter is just weird, and if everything is named that way then it's pointless because the capitalisation doesn't help distinguish different types of names (e.g. using a capital letter just for types makes it clear which names are types and which are not ... using it for everything is useless.)
I feel like this only complicates things a lot by having to check for nullptr everywhere. Also, moving a shared_ptr is a little bit silly.
edit:
I think I understand the problem now and this is how I would solve it:
struct Item {
std::list<std::shared_ptr<Item>> Children;
std::set < std::shared_ptr<Item>, std::owner_less < std::shared_ptr<Item >> > RemovedItems;
void Update();
void Remove(std::shared_ptr<Item>);
};
void Item::Update()
{
for (auto child : Children){
if (true) { // a complex condition, (true) is for demo purposes
RemovedItems.insert(child);
}
// A complex loop where children collection could be modified but
// only by calling Item::remove, Item::add or similar
}
auto oless = std::owner_less < std::shared_ptr < Item >>();
std::sort(Children.begin(), Children.end(), oless ); //to avoid use a set
auto newEnd = std::set_difference(Children.begin(),
Children.end(),
RemovedItems.begin(),
RemovedItems.end(),
Children.begin(),
oless);
Children.erase(newEnd, Children.end());
RemovedItems.clear(); // may call destructors on objects
}
void Item::Remove(std::shared_ptr<Item> element){
RemovedItems.insert(element);
}

Qt delete works with Valgrind but not normal execution

I'm checking for memory leaks in my Qt program using QtCreator and Valgrind. I am deleting a few entries in a QHash in my destructor like this:
QHash<QString, QVariant*> m_Hash;
/**
* #brief
* Destruct a Foo Class instance
*/
Foo ::~Foo ()
{
// Do Cleanup here
// Delete hash leftovers
foreach( QString key, m_Hash.keys() )
{
qDebug() << "Deleting an entry..";
// Delete the hash item
delete m_Hash.take(key);
}
}
If I debug with Valgrind this code is fine and deletes the contents when the destructor is called:
>> Deleting an entry..
>> Deleting an entry..
If I launch with GDB within QtCreator, launch without GDB from QtCreator, or just run my Qt App from the command line I get Segmentation Faults!
Signal name :
SIGSEGV
Signal meaning :
Segmentation fault
If I commend out the 'delete' line then I can run my app just fine using any method but I do leak memory.
What gives? Does valgrind introduce some sort of delay that allows my destructor to work? How can I solve this?
hyde's answer is correct; however, the simplest possible way to clear your particular hash is as follows:
#include <QtAlgorithms>
Foo::~Foo()
{
qDeleteAll(m_Hash);
m_Hash.clear();
}
Note that the above technique would not work if the key of the hash table was a pointer (e.g. QHash<QString*, QVariant>).
You can not modify the container you iterate over with foreach. Use iterators instead. Correct code using method iterator QHash::erase ( iterator pos ):
QMap<QString, QVariant* >::iterator it = m_Hash.begin();
// auto it = m_Hash.begin(); // in C++11
while (it != m_Hash.end()) {
delete it.value();
it = m_Hash.erase(it);
}
Also, any particular reason why you are storing QVariant pointers, instead of values? QVariant is usually suitable for keeping as value, since most data you'd store in QVariant is either implicitly shared, or small.
The documentation does not explicitly mention it, but it is a problem that you are mutating the container you are iterating over.
The code to foreach is here.
Looking at the code, it and your code do basically the same as if you'd write:
for (QHash::iterator it=m_Hash.begin(), end=m_Hash.end();
it!=end;
++it)
{
delete m_Hash.take(key);
}
however, the take member function may trigger an invalidation of existing iterators (it and end), so your iterators might have become dangling, yielding undefined behavior.
Possible solutions:
* do not modify the container you iterator over while iterating
* make sure it is valid before the next iteration begins, and don't store an end-iterator (this solution forbids the use of foreach)
Maybe there is problem with the foreach keyword. Try replacing:
foreach( QString key, m_Hash.keys() )
{
qDebug() << "Deleting an entry..";
delete m_Hash.take(key); // take changes the m_Hash object
}
with:
for (QHash<QString, QVariant*>::iterator it = m_Hash.begin();
it != m_Hash.end(); ++it)
{
qDebug() << "Deleting an entry..";
delete it.value(); // we delete only what it.value() points to, but the
// m_Hash object remains intact.
}
m_Hash.clear();
This way the hash table remains unchanged while you iterate through it. It is possible that the foreach macro expands into a construct where you "delete the hashtable from under your feet". That is the macro probably creates an iterator, which becomes invalid or "dangling" as a side effect of calling
m_Hash.take(key);