Monday, April 1, 2019

Digest for comp.lang.c++@googlegroups.com - 25 updates in 2 topics

Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 08:08AM +0200


> Of course there is: people want to know that an object referred
> to by an iterators remains stable nd they want to know when
> iterators become invalid ...
 
No, they won't in this case.
Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 08:36AM +0200

The thing is that .erase simply shifts the elements with th assignment
-operator and if I do the same with my own code like the following ...
 
template<typename T>
void vector_erase( vector<T> &v, typename vector<T>::iterator first,
typename vector<T>::iterator last )
{
typename vector<T>::iterator shiftOld,
shiftNew;
for( shiftOld = last, shiftNew = first; shiftOld != v.end(); )
*shiftNew++ = *shiftOld++;
v.resize( shiftNew - v.begin() );
}
 
.. the iterators to the vector remain valid until the place I cut
the vector.
Paavo Helde <myfirstname@osa.pri.ee>: Apr 01 11:41AM +0300

On 1.04.2019 0:52, Mr Flibble wrote:
 
> The iterator concept dictates that what an iterator refers to never
> changes unless the iterator itself is changed.
 
Consider two programs:
 
#include <iostream>
#include <vector>
#include <string>
 
int main() {
std::vector<std::string> v;
v.push_back("Alice");
v.push_back("Bob");
auto iter1 = v.begin();
std::cout << "I am "<< *iter1 << "\n";
v[0] = v[1];
v.erase(v.begin()+1);
std::cout << "Now I am "<< *iter1 << "\n";
}
 
---------------
 
#include <iostream>
#include <vector>
#include <string>
 
int main() {
std::vector<std::string> v;
v.push_back("Alice");
v.push_back("Bob");
auto iter1 = v.begin();
std::cout << "I am "<< *iter1 << "\n";
v.erase(v.begin());
std::cout << "Now I am "<< *iter1 << "\n";
}
 
According to the C++ standard the second program has UB when
dereferencing the invalidated iterator, whereas the first program is
fine. At the same time what they do seems to be very similar, so the
question is what is the motivation for the standard to make the second
one UB?
"Öö Tiib" <ootiib@hot.ee>: Apr 01 04:22AM -0700

On Monday, 1 April 2019 11:42:06 UTC+3, Paavo Helde wrote:
> fine. At the same time what they do seems to be very similar, so the
> question is what is the motivation for the standard to make the second
> one UB?
 
The second program above will currently crash when debugging
iterators. Online example with gcc:
http://coliru.stacked-crooked.com/a/148f26f38bfb7643
 
It is tricky to specify how the iterators are now valid but
somehow "reseated" to point at different elements. Lot of
defects are already because of people being confused
with iterators and dereferencing invalid ones. Additional
complications won't reduce those issues. Is there some
motivating example for defining the behavior in standard?

It feels somewhat similar to iterating over whole
multidimensional array by incrementing single pointer to
element. That likely works as intended on all current
platforms but is undefined behavior (AFAIK by both C
and C++ standards). The code will be confusing and the
whole idea smelly.
Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 02:17PM +0200

Am 01.04.2019 um 08:36 schrieb Bonita Montero:
> }
> .. the iterators to the vector remain valid until the place I cut
> the vector.
 
 
Oh, there's a minor difference in my implementation and what the
usual implementation seems to be: the assignment is applied with
the move-assignment-operator (i checked MSVC++ and g++) , i.e.
this ...
*shiftNew++ = *shiftOld++;
... has to be changed into this ...
*shiftNew++ = move( *shiftOld++ );
But is it really guaranteed by the standard that the move-assign-
ent-operator is used?
Paavo Helde <myfirstname@osa.pri.ee>: Apr 01 03:31PM +0300

On 1.04.2019 14:22, Öö Tiib wrote:
 
> The second program above will currently crash when debugging
> iterators. Online example with gcc:
> http://coliru.stacked-crooked.com/a/148f26f38bfb7643
 
Sure it will crash, as the debugging iterators have been programmed to
detect UB as specified by the standard.
 
> defects are already because of people being confused
> with iterators and dereferencing invalid ones. Additional
> complications won't reduce those issues.
 
If so, why does the standard contain special verbiage that the iterators
to elements *before* the erased range remain valid? It would be much
simpler to say that an erase() call will invalidate all iterators.
 
Now, if I have some random iterator into the vector, this might or might
not be invalidated, depending on where the erasure occurred, how is that
simpler to keep track than to make sure the iterator still points inside
the final valid vector range.
 
> complications won't reduce those issues. Is there some
> motivating example for defining the behavior in standard?
 
I'm not suggesting that this behavior should be defined, I was just
trying to translate Bonita's question.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 01 02:13PM +0100

On 01/04/2019 13:31, Paavo Helde wrote:
 
> If so, why does the standard contain special verbiage that the iterators
> to elements *before* the erased range remain valid? It would be much
> simpler to say that an erase() call will invalidate all iterators.
 
Because the object identity of the elements before the erased range are
not changed so it makes sense for iterators referring to them to remain
valid. This is not the case for elements after the point of erasure.
 
Ask yourself why this behaviour is the case for std::vector but isn't the
case for std::list. This is all about object identity and what it means
for an object to change.
 
/Flibble
 
--
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Paavo Helde <myfirstname@osa.pri.ee>: Apr 01 05:12PM +0300

On 1.04.2019 16:13, Mr Flibble wrote:
 
> Because the object identity of the elements before the erased range are
> not changed so it makes sense for iterators referring to them to remain
> valid. This is not the case for elements after the point of erasure.
 
So what's the identity of an object? As we all know, an object is a
region of storage. Object also has lifetime which is ended by the
destructor call. However, the standard specifically says that in a
vector::erase() call, the destructor is called only for erased elements,
for moving around the other stuff move operations are used:
 
23.3.6.5/4 [vector.modifiers] "Complexity: The destructor of T is called
the number of times equal to the number of the elements erased."
 
Now consider a vector v of 3 elements:
 
v[0], v[1], v[2]
 
If I erase v.begin(), v[0] is indeed destroyed. However, v[1] is
move-constructed at the location of v[0], and v[2] is move-assigned to
v[1]. So the second element v[1] resides at the same memory location, is
of the same type and has never seen a destructor call. It was just
assigned a new value, that's all.
 
So at which point did the v[1] object identity change now?
Paavo Helde <myfirstname@osa.pri.ee>: Apr 01 05:25PM +0300

On 1.04.2019 17:12, Paavo Helde wrote:
 
> Now consider a vector v of 3 elements:
 
> v[0], v[1], v[2]
 
> If I erase v.begin(), v[0] is indeed destroyed.
 
Correction: after re-reading the standard I now see v[0] is not
destroyed either, it is move-assigned from v[1]. Only v[2] gets
destroyed. So, even more to the point, object lifetime has not ended for
none of the remaining elements, why should iterators to them become invalid?
 
Also note that pointers and references to these elements remain valid
(3.8/7 [basic.lifetime]).
"Öö Tiib" <ootiib@hot.ee>: Apr 01 07:49AM -0700

On Monday, 1 April 2019 15:31:56 UTC+3, Paavo Helde wrote:
> > http://coliru.stacked-crooked.com/a/148f26f38bfb7643
 
> Sure it will crash, as the debugging iterators have been programmed to
> detect UB as specified by the standard.
 
If it wasn't UB then there still would be frequently enough real
programming error. It feels similar like how static analyzers
warn about calling virtual functions from constructors and
destructors. That is well-defined but quite commonly there is
actual programming error.

 
> If so, why does the standard contain special verbiage that the iterators
> to elements *before* the erased range remain valid? It would be much
> simpler to say that an erase() call will invalidate all iterators.
 
That is also complication, indeed. The difference is that it is
simpler to express and to understand. The element to what
the iterator (before erased range) is pointing is exactly same
element as it was before erase.
 
> not be invalidated, depending on where the erasure occurred, how is that
> simpler to keep track than to make sure the iterator still points inside
> the final valid vector range.
 
When (algorithm is such that) it is unclear if an iterator was
or wasn't invalidated then it is likely simplest to assume that
it was. Same as with push_back, when (algorithm is such that)
it is unsure if reallocation occurred or not then it is simplest
to assume that it did and so all iterators are invalid.
 
> > motivating example for defining the behavior in standard?
 
> I'm not suggesting that this behavior should be defined, I was just
> trying to translate Bonita's question.
 
I am still interested on what case such stored iterators (or
references or pointers) at "potentially shifted elements" are
handy to have and not confusing
Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 04:56PM +0200

> If I erase v.begin(), ...
 
No, it is copy-assigned with the following element.
So there's no identity-change.
Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 04:57PM +0200

> If I erase v.begin(), ...
 
No, it is move-assigned with the following element.
So there's no identity-change.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 01 03:58PM +0100

On 01/04/2019 15:12, Paavo Helde wrote:
> call. However, the standard specifically says that in a vector::erase()
> call, the destructor is called only for erased elements, for moving around
> the other stuff move operations are used:
 
Object identity is unrelated to object lifetime; it is an abstract
semantic property of an object referring to its identity with respect to
the rest of an abstract system.
 
/Flibble
 
--
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 01 04:00PM +0100

On 01/04/2019 15:57, Bonita Montero wrote:
>> If I erase v.begin(), ...
 
> No, it is move-assigned with the following element.
> So there's no identity-change.
 
Obviously you do not understand what object identity means: the object
"becomes" another object so its identity has changed even though its
storage location and/or object lifetime has not changed.
 
/Flibble
 
--
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Bonita Montero <Bonita.Montero@gmail.com>: Apr 01 05:47PM +0200


> Obviously you do not understand what object identity means: the object
> "becomes" another object so its identity has changed even though its
> storage location and/or object lifetime has not changed.
 
That can't be true because if you change a single member of an object
this would invalidate the iterator "pointing" at it.
Melzzzzz <Melzzzzz@zzzzz.com>: Apr 01 03:14AM


>>You said it is difficult. It is not.
 
> Any idiot can wrap a lambda, I meant passing one direct to pthread_create().
> Show us your code for that.
 
So you are bellow level of idiot?
 
--
press any key to continue or any other to quit...
blt_mm@5c_mkufnilan750.co.uk: Apr 01 09:24AM

On Sun, 31 Mar 2019 13:18:21 -0400
>The statement "Getting lambdas to work with threads" is logically equivalent
>to "making elephants fly with automobiles".
 
Perhaps you should share your insights about that with the C++ steering
committee since they did exactlty that. Not sure how they're getting on
with the elephants however.
 
>> Truly a savant and nobel prizes surely await you!
 
>I'll decline. I don't like traveling.
 
I guess it can be scary coming out of your parents basement.
blt_fyaj1g2q@3wg.ac.uk: Apr 01 09:26AM

On 31 Mar 2019 19:20:34 GMT
>90% of the postings here.
 
>At the same time, you /know/ you're now turning it into the same old
>flamewar.
 
The older I get the less tolerant I am of idiot trolls on usenet.
blt_k93y@5nnj1zezih7uyebzv1zvpzlbp.gov: Apr 01 09:30AM

On Mon, 01 Apr 2019 03:14:59 GMT
 
>> Any idiot can wrap a lambda, I meant passing one direct to pthread_create().
>> Show us your code for that.
 
>So you are bellow level of idiot?
 
Bellow level? Is that where people shout a lot but don't actually say
anything useful? I'm sure you'd be right at home there.
David Brown <david.brown@hesbynett.no>: Apr 01 12:10PM +0200


>> At the same time, you /know/ you're now turning it into the same old
>> flamewar.
 
> The older I get the less tolerant I am of idiot trolls on usenet.
 
Surely you are smart enough to figure out the best course of action. I
don't think you will be missed.
Sam <sam@email-scan.com>: Apr 01 06:57AM -0400


> Perhaps you should share your insights about that with the C++ steering
> committee since they did exactlty that. Not sure how they're getting on
> with the elephants however.
 
I doubt that you are capable of comprehending of what the C++ steering does
or doesn't do. It's obviously above your pay level.
Sam <sam@email-scan.com>: Apr 01 07:00AM -0400


> The older I get the less tolerant I am of idiot trolls on usenet.
 
Metamucil is cheap.
blt_i0cn@g7zdtja.org: Apr 01 11:04AM

On Mon, 01 Apr 2019 07:00:22 -0400
 
>blt_fyaj1g2q@3wg.ac.uk writes:
 
>> The older I get the less tolerant I am of idiot trolls on usenet.
 
>Metamucil is cheap.
 
So thats what you take. Explains why you post so much shit.
Sam <sam@email-scan.com>: Apr 01 08:33AM -0400


> >> The older I get the less tolerant I am of idiot trolls on usenet.
 
> >Metamucil is cheap.
 
> So thats what you take. Explains why you post so much shit.
 
You're just incapable of fully comprehending my greatness. Hence my
suggestion.
 
P.S. Happy birthday!
blt_e5@l9ghrtg9hdkmdxd43u9.net: Apr 01 02:14PM

On Mon, 01 Apr 2019 08:33:23 -0400
 
>You're just incapable of fully comprehending my greatness. Hence my
>suggestion.
 
>P.S. Happy birthday!
 
Sadly my birthday is months away but April 1st is probably yours.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: