Set iterator invalidated by move semantic - c++

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.

Related

Boost.PropertyTree crash when iterating over some empty trees

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.

STL: Create vector<T*> from vector<T> when T(const T&) is deleted

How can I create std::vector<T*> from std::vector<T> when copy constructor T(const T&) is deleted?
Why do I need this?
- Our threading(tbb) functor requires vector of T*.
// sample code
std::vector<T> vt;
std::vector<T*> vtp;
for (...)
{
T a;
a.build(args...); // 'build()' rebuilds the point tree
vt.push_back(a);
}
// store T pointer in vtp
for (auto i = vt.begin(); i != vt.end(); i++)
vtp.emplace_back(&*i); // error: use of deleted function 'T::T(const T&)'
Since I'm creating T object a in a loop so I can't(uniquely) store a* directly into vtp as it would be overwritten on the same address. I'm using C++11 and GCC4.8.
I've an alternative solution:
T t_a1, t_a2, t_a3, t_a4;
vtp = {&t_a1, &t_a2, &t_a3, &t_a4};
for (...)
{
(vtp[pageIdx])->build(args...); // pageIdx is block index in current range block
}
In this approach I need to build certain number of the trees in advance. Although, I can easily calculate the number of trees by getting the number of blocks in the range. But I want to avoid manual creation of the tree in advance and I'm not sure whether it would be efficient.

C++ Unexpected error when deleting objects

I write an interpreter, in which each keyword, syntax notation or operator has the base class of Token.
class Token {
private:
static std::vector<Token *> registered;
size_t id;
std::string name;
std::string symbol;
public:
Token(const std::string& Name, const std::string& Symbol);
Token::~Token();
Token(const Token& rhs) = delete;
Token& operator =(const Token& rhs) = delete;
/* ... */
static void DeleteRegistered();
};
The constructor:
Token::Token(const std::string& Name, const std::string& Symbol)
: name(Name), symbol(Symbol) {
Token::registered.push_back(this);
this->id = Token::registered.size();
}
The destructor:
Token::~Token() {
// Removes 'this' from Token::registered
Token::registered.erase(std::remove(Token::registered.begin(), Token::registered.end(), this), Token::registered.end());
}
DeleteRegistered:
void Token::DeleteRegistered() {
for (size_t i = 0; i < Token::registered.size(); ++i) {
delete Token::registered[i];
}
}
In my code, many different classes store containers of pointers to sub-classes which eventually derive from Token.
In order to avoid deleting objects twice or more, I store references to all of the allocated instances, and have a static method which will delete them all.
The method DeleteRegistered is called after all operations are done executing.
Now, to my problem:
When I call Token::DeleteRegistered (which happens a few lines before the program exits, it fails and in debug shows the following:
File: f:\dd\vctools\crt\crtw32\misc\dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Since all of the Token instances don't really have a defined scope, I came up with this design, which to me currently seems OK.
What can cause this error?
EDIT:
The destructor was a late addition of mine, commenting it out still shows the error above. The delete fails to delete even the first item in the container.
2ND EDIT:
An example of how I use Token:
this->parser.Operators.Add(new RefBinaryOperator(
"Assignment", "=", 14, RefBinaryOperator::Assign
));
Note: RefBinaryOperator is a sub-class of Token (Not direct), which eventually calls Token's constructor.
So for instance, I pull pointers to Tokens from the Operators container, and assign them to other structures. When everything is done, I call DeleteRegistered.
FINAL EDIT:
I got it working by declaring the Token destructor as virtual:
Does delete work with pointers to base class?
What is happening is that in Token::~Token() you are calling erase from the registered vector which is invalidating the indices used in the for loop where you noticed the problem. You need to remember that once you call erase on that vector, the for loop indices need to be adjusted properly. If you keep your current destructor the following could work in DeleteRegistered:
void DeleteRegistered() {
while(!Token::registered.empty())
delete *Token::registered.begin();
}
Also, since you have many classes which extend off of Token, ~Token() should become virtual so that the destruction for the base class will be properly handled.
void Token::DeleteRegistered() {
for (size_t i = 0; i < Token::registered.size(); ++i) {
delete Token::registered[i];
}
}
The above will not do what you want. It's going to remove the first (0th) element from registered. What was the second element now becomes the first (0th element), but now i will be 1. Your loop will remove only every other element from Token::registered. It leaks.
One way to handle this: Keep removing either the first or last element while the vector is not empty. I'd suggest deleting the last element because that's more consistent with how vectors work. Deleting the first element until the vector is empty involves rebuilding the vector each step.
void Token::DeleteRegistered() {
while (! Token::registered.empty()) {
delete Token::registered.back();
}
}

Can't Save structure content

I have the next problem:
I created the structure:
struct Series : vector<Candle>
{
Security Sec;
int LookFor;
int TF;
int Corrector;
string ID;
int line;
Series(){};
Series (int _lookfor);
void Update();
};
Constructor:
Series::Series (int _lookfor)
{
LookFor=_lookfor;
for (int i = 1; i<=LookFor; i++)
{
Candle cantype = Candle(i);
push_back(cantype);
}
}
So, then we call this construcor it fills object by candle-values. LookFor - is a number of candles in the vector-series.
After initialization i want update this serie (if there is more new candle, i want delete last one and insert new on the begining of vector-serie)
void Series::Update()
{
if (size()==LookFor)
{
if (newer(cantype,c1))
{
Candle cantype = Candle(1);
Candle c1 = at(0);
pop_back();
emplace(begin(),cantype);
}
}
I need to initialize a vector of these series:
vector vec;
vec.push_back(Series(3));
And constructor does its job, everithing is fine.
But then i update them:
for (size_t x =0; x<=size()-1;x++) vec[x].Update();
I have a problem: it cann't save changes in vector. In Update method everithing is fine, it inserts needed candle in itself, but then method is ended - the state of vector (each element of vec) has no changes. In method we see changes, but after it vector become after constructor-like, the state still the same.
Tell me, please, what am I doing wrong?
As others already mentioned, do not derive from these containers (could cause nasty errors like missing dtor calls and memory leaks, no virtual destructor is present in these containers). Instead, add the vector as a member or leave it as is, if you do private inheritance.
You may use the iterator interface for such containers:
for(std::vector<Series>::iterator sIt = vec.begin();sIt != vec.end();++sIt) sIt->Update();
For your task, consider using a deque or a list as a circular buffer instead of the vector for the Candles. It would perform better for insertions and therefore allows you to use push_front() instead of emplace() or insert().
Alternatively, you could hold an index of the vector element just past the last element (which should be the first) and just assign the new candle, et voilĂ , you've got a dense circular buffer.
There are implementations of such circular buffers, for example the one of boost:
http://www.boost.org/doc/libs/1_52_0/libs/circular_buffer/doc/circular_buffer.html
Despite logic issues, which could prevent the modification in certain states, I can't see, why your code doesn't work at all, at least not when I went through the snippets you posted.

question about std::vector::end()

I recently finished fixing a bug in the following function, and the answer surprised me. I have the following function (written as it was before I found the bug):
void Level::getItemsAt(vector<item::Item>& vect, const Point& pt)
{
vector<itemPtr>::iterator it; // itemPtr is a typedef for a std::tr1::shared_ptr<item::Item>
for(it=items.begin(); it!=items.end(); ++it)
{
if((*it)->getPosition() == pt)
{
item::Item item(**it);
items.erase(it);
vect.push_back(item);
}
}
}
This function finds all Item objects in the 'items' vector that has a certain position, removes them from 'items', and puts them in 'vect'. Later, a function named putItemsAt does the opposite, and adds items to 'items'. The first time through, getItemsAt works fine. After putItemsAt is called, though, the for loop in getItemsAt will run off the end of 'items'. 'it' will point at an invalid Item pointer, and getPosition() segfaults. On a hunch, I changed it!=items.end() to it<items.end(), and it worked. Can anyone tell me why? Looking around SO suggests it might involve erase invalidating the iterator, but it still doesn't make sense why it would work the first time through.
I'm also curious because I plan to change 'items' from a vector to a list, since list's erase is more efficient. I know I'd have to use != for a list, as it doesn't have a < operator. Would I run into the same problem using a list?
When you call erase(), that iterator becomes invalidated. Since that is your loop iterator, calling the '++' operator on it after invalidating it is undefined behavor. erase() returns a new valid iterator that points to the next item in the vector. You need to use that new iterator from that point onwards in your loop, ie:
void Level::getItemsAt(vector<item::Item>& vect, const Point& pt)
{
vector<itemPtr>::iterator it = items.begin();
while( it != items.end() )
{
if( (*it)->getPosition() == pt )
{
item::Item item(**it);
it = items.erase(it);
vect.push_back(item);
}
else
++it;
}
}
You're invoking undefined behavior. All the iterators to a vector are invalidated by the fact that you called erase on that vector. It's perfectly valid for an implementation to do whatever it wants.
When you call items.erase(it);, it is now invalid. To conform to the standard, you must now assume that it is dead.
You invoke undefined behavior by using that invalid iterator in the next call to vect.push_back.
You invoke undefined behavior again by using it as the tracking variable of your for loop.
You can make your code valid by using std::remove_copy_if.
class ItemIsAtPoint : std::unary_function<bool, item::Item>
{
Point pt;
public:
ItemIsAtPoint(const Point& inPt) : pt(inPt) {}
bool operator()(const item::Item* input)
{
return input->GetPosition() == pt;
}
};
void Level::getItemsAt(vector<item::Item>& vect, const Point& pt)
{
std::size_t oldSize = items.size();
std::remove_copy_if(items.begin(), items.end(), std::back_inserter(vect),
ItemIsAtPoint(pt));
items.resize(vect.size() - (items.size() - oldSize));
}
You can make this a lot prettier if you are using boost::bind, but this works.
I'll go with Remy Lebeau's explanation about iterator invalidation, and just add that you can make your code valid and asymptotically faster (linear time, instead of quadratic time) by using a std::list instead of a std::vector. (std::list deletions only invalidate the iterator that was deleted, and insertions don't invalidate any iterators.)
You can also predictibly identify iterator invalidation while debugging by activating your STL implementation's debug mode. On GCC, you do with with the compiler flag -D_GLIBCXX_DEBUG (see some caveats there).