473,386 Members | 1,745 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Runs with GCC, crashes with MSVC

#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?
Jul 22 '05 #1
10 1435
Derek wrote:
#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
pop_back invalidates the iterator what pointed to the popped element.
In your case, since 'it' is a reverse iterator, it really points to
the element right after the one it gives when dereferenced. It's just
one of the iterator implementation tricks, I suppose. So, when you
say it = foo.rbegin(), it basically the same as it = foo.end(), but
with a twist. Now, it++ moves it to point to the last element, which
you promptly pop in the next statement. The iterator is invalid after
that.
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?


Both are right. You're trying to make use of an invalid iterator,
and therefore get undefined behaviour.

You probably should have done

while (!foo.empty())
{
cout << "start of loop\n;
int temp = *foo.rbegin(); // or int temp = foo.back();
foo.pop_back();
}

Victor
Jul 22 '05 #2
Derek <us**@nospam.org> wrote in news:2l************@uni-berlin.de:
#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?


Both :) According to Josuttis, you're working with an invalidated
iterator.

"Thus, any insertion or deletion invalidates all pointers, references,
and iterators that refer to other elements of the deque. The exception
is when elements are inserted at the front or the back."
Jul 22 '05 #3
Andre Kostur wrote:
Derek <us**@nospam.org> wrote in news:2l************@uni-berlin.de:

#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?

Both :) According to Josuttis, you're working with an invalidated
iterator.

"Thus, any insertion or deletion invalidates all pointers, references,
and iterators that refer to other elements of the deque. The exception
is when elements are inserted at the front or the back."


Actually popping from the front or from the back, according to the
Standard, invalidates only the iterators that point to those objects.
The trouble is, the reverse iterators really point to the object one
past the one you think they point to.

Of course, Josuttis' rule is a bit more strict, so if you follow it,
you are less likely to make a mistake, although, you'd be restricted
more (..yeah, I suppose that's what 'strict' means, more restrictions,
right?...)

Victor
Jul 22 '05 #4
Victor Bazarov wrote:

pop_back invalidates the iterator what pointed to
the popped element. In your case, since 'it' is a
reverse iterator, it really points to the element
right after the one it gives when dereferenced.
It's just one of the iterator implementation tricks,
I suppose. So, when you say it = foo.rbegin(),
it basically the same as it = foo.end(), but with
a twist. Now, it++ moves it to point to the
last element, which you promptly pop in the next
statement. The iterator is invalid after that.
Thanks, Victor. I had to think about it for a few
minutes, but that makes sense.
You probably should have done

while (!foo.empty())
{
cout << "start of loop\n;
int temp = *foo.rbegin();
foo.pop_back();
}


Then maybe I can't do what I need with a deque. In
the full program the pop_back is conditional. What
I wanted is to iterate over all elements in reverse
and pop_back only if it meets some condition and
exit the loop otherwise:

#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
if (condition(temp))
foo.pop_back();
else
break;
}
return 0;
}
Jul 22 '05 #5
Derek wrote:
Victor Bazarov wrote:
>
> pop_back invalidates the iterator what pointed to
> the popped element. In your case, since 'it' is a
> reverse iterator, it really points to the element
> right after the one it gives when dereferenced.
> It's just one of the iterator implementation tricks,
> I suppose. So, when you say it = foo.rbegin(),
> it basically the same as it = foo.end(), but with
> a twist. Now, it++ moves it to point to the
> last element, which you promptly pop in the next
> statement. The iterator is invalid after that.


Thanks, Victor. I had to think about it for a few
minutes, but that makes sense.
> You probably should have done
>
> while (!foo.empty())
> {
> cout << "start of loop\n;
> int temp = *foo.rbegin();
> foo.pop_back();
> }


Then maybe I can't do what I need with a deque. In
the full program the pop_back is conditional. What
I wanted is to iterate over all elements in reverse
and pop_back only if it meets some condition and
exit the loop otherwise:

#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
if (condition(temp))
foo.pop_back();
else
break;
}
return 0;
}


The correct way to write this would be

while (condition(foo.back()))
foo.pop_back();

Victor
Jul 22 '05 #6

"Derek" <us**@nospam.org> wrote in message news:2l************@uni-berlin.de...

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?


Hmm... the operative rule is that "an erase at either end of the deque invalidates
only the interators and references to the erased elements." Your iterator is pointing
at rend() which isn't the erased element, so it should fail the while() test the second
time around.

Jul 22 '05 #7
On Fri, 16 Jul 2004 11:15:39 -0700, Derek wrote:
#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();

while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
The use of a post-increment operator is essential here. The two lines
above is effectively the equivalent of these lines:

deque<int>::reverse_iterator tempIter = it;
++it;
int temp = *tempIter;
foo.pop_back();

If ++it line was put after pop_back, I can understand how it would be
undefined behavior. But when there is only one item, 'it' now should
be equal to foo.rend(); not invalid.

What is invalid is the temporary iterator (tempIter) that the compiler
generates to accomplish the post-increment operation. We never touch
that inaccessible temporary.
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints "start of loop"
once and exits gracefully (as I would expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of loop" twice and
crashes.

Who is right?


The way I understand it, g++ is behaving correctly
here. Implementation details should not matter because you are not
using an invalid iterator.

Ali
Jul 22 '05 #8
On Fri, 16 Jul 2004 15:25:50 -0700, Ali Cehreli wrote:
On Fri, 16 Jul 2004 11:15:39 -0700, Derek wrote:
#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();

while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
The use of a post-increment operator is essential here. The two lines
above is effectively the equivalent of these lines:

deque<int>::reverse_iterator tempIter = it;
++it;
int temp = *tempIter;
foo.pop_back();


I don't this this is relevant or even interesting here :)
What is invalid is the temporary iterator (tempIter) that the compiler
generates to accomplish the post-increment operation. We never touch
that inaccessible temporary.
[...]
Implementation
details should not matter because you are not using an invalid iterator.


I don't think so anymore :)

I guess if an iterator is invalid, even comparing it with another
iterator should be considered as using it. I don't think even that
would be valid.

#include <deque>
#include <assert.h>

int main()
{
typedef std::deque<int> Numbers;

Numbers numbers;
numbers.push_back(42);

Numbers::iterator it = numbers.begin();
++it;

// We must be at the end
assert(it == numbers.end());

numbers.pop_back();

// Now is this check legal? (I don't think so.)
assert(it == numbers.end());
}

Ali
Jul 22 '05 #9

"Derek" <us**@nospam.org> schrieb im Newsbeitrag
news:2l************@uni-berlin.de...
#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
foo.pop_back();
}
return 0;
}

When compiled with GCC 3.3.1, the program above prints
"start of loop" once and exits gracefully (as I would
expect it to do).

When compiled with MSVC 6 (SP6), it displays "start of
loop" twice and crashes.

Who is right?

Seems foo.rend() ist changed throuch foo.pop_back().
Try this:
----------------------------------------------------------------------------
---
deque<int>::reverse_iterator it_end = foo.rend();
while (it != it_end)
{
int temp = *it++;
foo.pop_back();
}
----------------------------------------------------------------------------
---
Greetings
Roland
Jul 22 '05 #10
On Fri, 16 Jul 2004 19:59:17 GMT, Victor Bazarov
<v.********@comAcast.net> wrote:
Derek wrote:
Victor Bazarov wrote:
>
> pop_back invalidates the iterator what pointed to
> the popped element. In your case, since 'it' is a
> reverse iterator, it really points to the element
> right after the one it gives when dereferenced.
> It's just one of the iterator implementation tricks,
> I suppose. So, when you say it = foo.rbegin(),
> it basically the same as it = foo.end(), but with
> a twist. Now, it++ moves it to point to the
> last element, which you promptly pop in the next
> statement. The iterator is invalid after that.


Thanks, Victor. I had to think about it for a few
minutes, but that makes sense.
> You probably should have done
>
> while (!foo.empty())
> {
> cout << "start of loop\n;
> int temp = *foo.rbegin();
> foo.pop_back();
> }


Then maybe I can't do what I need with a deque. In
the full program the pop_back is conditional. What
I wanted is to iterate over all elements in reverse
and pop_back only if it meets some condition and
exit the loop otherwise:

#include <deque>
#include <iostream>
using namespace std;

int main()
{
deque<int> foo;
foo.push_back(42);
deque<int>::reverse_iterator it = foo.rbegin();
while (it != foo.rend())
{
cout << "start of loop\n";
int temp = *it++;
if (condition(temp))
foo.pop_back();
else
break;
}
return 0;
}


The correct way to write this would be

while (condition(foo.back()))
foo.pop_back();


rather:

while (!foo.empty() && condition(foo.back()))
foo.pop_back();

Tom
Jul 22 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Eric Brunel | last post by:
Hi all, We're trying to communicate with Microsoft Visual C++ 6.0 via COM to make it perform a few operations. Our main need is to set a breakpoint on a given line in a given file. We ended up...
2
by: AIM | last post by:
Error in msvc in building inheritance.obj to build hello.pyd Hello, I am trying to build the boost 1.31.0 sample extension hello.cpp. I can not compile the file inheritance.cpp because the two...
4
by: Jacek Dziedzic | last post by:
Hi! First of all, I hope my problem is not too loosely tied to the "standard C++" that is the topic of this group. I have some code that exhibits a strange behaviour: on one computer, where I...
0
by: Leor Zolman | last post by:
The Intel C++ version of STLFilt (my STL Error Message Decryptor utility) has now been updated to support Intel C++ 8 (currently in Beta) along with version 7. All three MSVC libraries are...
12
by: Paul | last post by:
Hi, Global operator new and delete are overloaded and I am using stl map to store pointers, but this code crashes, can some one shed some light??? Compiler: MS VC++ 6.0 STL: Shipped with...
8
by: Chris Stankevitz | last post by:
I can't tell you how frusterated I and my coworkers are with "MSVC 7.1 .net 2003" (what am I supposed to call this thing anyway?). Compiling and linking take twice as long with "MSVC 7.1 .net...
0
by: =?Utf-8?B?QmFjaA==?= | last post by:
Hi, I have a ASP.NET 2.0 web service, which runs beautifully when hosted in the development server of VS2005 (out side of IIS) but crashes when hosted inside IIS 5.1 or IIS 6.0 when it takes...
41
by: z | last post by:
I use Visual C 2005 to develop my programs. One in particular is crashing in very specific and hard to replicate situations, made worse by the fact it only crashes when run -outside- the dev - as...
2
by: BruceWho | last post by:
I downloaded boost1.35.0 and built it with following command: bjam --toolset=msvc-7.1 --variant=release --threading=multi -- link=shared --with-system stage and it failed to compile, error...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.