Should an iterator be valid after appending to a Glib::ustring?

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Should an iterator be valid after appending to a Glib::ustring?

Gtkmm mailing list
Are iterators into a Glib::ustring still valid after the string is
modified?  Specifically appended to or modified at or beyond where the
iterator points.  Especially if appending to the string causes the
underlying bytes to be relocated to a larger allocation.  I didn't
obviously see this mentioned in the documentation.

I though it might be valid because the iterator appears to be
implemented using a pointer difference type.  However the following
small test program fails with:
  **
  ERROR:test.cc:28:int main(): assertion failed: (linestart <= cursor)
  Aborted

Thanks,
Mike

--8<-- test.cc --8<--
#include <glib.h>
#include <glibmm/ustring.h>

int main()
{
    Glib::ustring buf;
    Glib::ustring::iterator linestart = buf.begin();
    Glib::ustring::iterator cursor = buf.begin();
    gunichar uc = 'u';
    buf.append(1, uc);
    cursor = buf.end();
    g_assert(buf.begin() <= linestart);
    g_assert(linestart <= cursor);
    g_assert(cursor <= buf.end());
    return 0;
}
_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: Should an iterator be valid after appending to a Glib::ustring?

Daniel Boles
It is a general concept of C++ that iterators are invalidated by various modifying operations, and the API should usually specify which operations do and do not invalidate iterators.


In this case, if ustring itself does not stipulate, you should check the Standard C++ documentation for std::string - as ustring is mostly a thin wrapper around that giving Unicode semantics. However,

Specifically appended to or modified at or beyond where the
iterator points.  Especially if appending to the string causes the
underlying bytes to be relocated to a larger allocation.  I didn't
obviously see this mentioned in the documentation.

This is a pretty obvious "no". If the operation can cause a reallocation, that's a very strong hint, so if the container does not explicitly state that it does NOT invalidate iterators.... then it does. Again, ustring will follow std::string here, where I know this not to be valid.


I though it might be valid because the iterator appears to be
implemented using a pointer difference type.  However the following
small test program fails with:

Well, it's a difference _from a particular base address_, isn't it? If reallocation occurs, that address changes, so the iterator now offsets into memory that no longer belongs to its instance.


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: Should an iterator be valid after appending to a Glib::ustring?

Daniel Boles
On 13 March 2017 at 21:46, Daniel Boles <[hidden email]> wrote:
This is a pretty obvious "no". If the operation can cause a reallocation, that's a very strong hint, so if the container does not explicitly state that it does NOT invalidate iterators.... then it does

I really meant 'increase the capacity', not 'reallocation', if we use 'reallocation' in the sense of moving existing elements, not just allocating other memory for new ones. So reallocation in this sense should always invalidate iterators. And since ustring (and std::string) is a random-access container, it must have contiguous memory, so any increase in capacity must cause a reallocation. So, any insert/append or anything else that adds elements.

but there's a point: if you had previously reserve()d enough capacity, beyond the current size, for the insert point and length, then as long as you stay within the capacity you had, your iterators should remain valid, as reallocation is guaranteed not to occur in such cases.


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: Should an iterator be valid after appending to a Glib::ustring?

Gtkmm mailing list
What about ustring.end() iterator? I think it's obvious that it's invalidated each time we change the string's length (unless it's done in some *very clever* way).
It's a thing no reserve()-ation can help.

-------- Original Message --------
Subject: Re: Should an iterator be valid after appending to a Glib::ustring?
Local Time: 13 marca 2017 10:50 PM
UTC Time: 13 marca 2017 21:50

On 13 March 2017 at 21:46, Daniel Boles <[hidden email]> wrote:
This is a pretty obvious "no". If the operation can cause a reallocation, that's a very strong hint, so if the container does not explicitly state that it does NOT invalidate iterators.... then it does

I really meant 'increase the capacity', not 'reallocation', if we use 'reallocation' in the sense of moving existing elements, not just allocating other memory for new ones. So reallocation in this sense should always invalidate iterators. And since ustring (and std::string) is a random-access container, it must have contiguous memory, so any increase in capacity must cause a reallocation. So, any insert/append or anything else that adds elements.
but there's a point: if you had previously reserve()d enough capacity, beyond the current size, for the insert point and length, then as long as you stay within the capacity you had, your iterators should remain valid, as reallocation is guaranteed not to occur in such cases.


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: Should an iterator be valid after appending to a Glib::ustring?

Daniel Boles
On 14 March 2017 at 14:29, Krzysztof Piecuch via gtkmm-list <[hidden email]> wrote:
What about ustring.end() iterator? I think it's obvious that it's invalidated each time we change the string's length (unless it's done in some *very clever* way).
It's a thing no reserve()-ation can help.

Right, yeah. Whether an iterator can remain valid also depends on what it represents, and .end() is especially vulnerable. Good point!


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: Should an iterator be valid after appending to a Glib::ustring?

Hubert Figuière-2
On 14/03/17 10:39 AM, Daniel Boles wrote:

> On 14 March 2017 at 14:29, Krzysztof Piecuch via gtkmm-list <
> [hidden email]> wrote:
>
>> What about ustring.end() iterator? I think it's obvious that it's
>> invalidated each time we change the string's length (unless it's
>> done in some *very clever* way). It's a thing no reserve()-ation
>> can help.
>>
>
> Right, yeah. Whether an iterator can remain valid also depends on
> what it represents, and .end() is especially vulnerable. Good point!

The simple rule: mutating the container cause iterators to be
invalidated, unless if explicitly said otherwise, like std::list<>.

http://en.cppreference.com/w/cpp/container/list

> Addition, removal and moving the elements within the list or across
> several lists does not invalidate the iterators or references. An
> iterator is invalidated only when the corresponding element is
> deleted.


Hub

_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list