Topic: std::list


Author: hinnant@metrowerks.com (Howard Hinnant)
Date: Tue, 4 Nov 2003 07:26:22 +0000 (UTC)
Raw View
In article <bngh17$hm$1@phys-news1.kolumbus.fi>,
 someone@microsoft.com ("wogston") wrote:

> Greets. I don't quite find this from the documentation on the net, and I
> don't have the ANSI documentation.
>
> Does std::list  ::assign() and ::insert() support copying from the same
> object? Example:
>
> std::list<int> v;
> for ( int i=0; i<10; ++i )
>   v.push_back(i);
>
> std::list<int>::iterator itr = v.begin();
> v.insert( itr, v.begin(), v.end() );
>
> .. is this defined, or undefined? I'm assuming it is defined, because online
> documentation such as Dinkumware's and MSDN don't say anything about any
> limitations, but want to be sure. Apologies if this is a stupid question.

No, this pattern is not supported by the standard.  A precondition on
these functions is that the iterators do not reference values in the
object being modified (reference 23.1.1/4).

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: someone@microsoft.com ("wogston")
Date: Tue, 4 Nov 2003 18:38:50 +0000 (UTC)
Raw View
> No, this pattern is not supported by the standard.  A precondition on
> these functions is that the iterators do not reference values in the
> object being modified (reference 23.1.1/4).

Oh, okay, so it is OK to assert for self-assignment? Actually, I have two
options:

- drop the "list*" member variable for self-assignment detection in iterator
- keep it, and assert

The first choise would be less overhead, just let undefined behaviour fall
at no runtime cost, to client's head if he invokes it.. I did manage to
write *very* efficient ::assign() and ::insert() when the controlled
sequence between "first" and "last" was within the container.

1)
::assign()

erase() elements before, and after the sequence.

2)
::insert()

Create a new sequence while iterating the input one, then glue it between
"it" and "--it", for the implementation I practised on this was trivial. I
had it in "traditional" implementation with next and prev pointer in the
internal node struct, which implemented the linked list (used iterators
merely as front-end). I recently wrote alternative implementation with node
storing only prev^next, in this implementation I haven't yet "optimized" the
::append() and ::insert(), but glad to hear that don't have to. ;-)

(I shall drop the container member, and the asserts.. unless I misunderstood
what you wrote above, in which case I will be glad to be corrected)

Here's what I've got so far:

http://www.liimatta.org/misc/list.hpp
http://www.liimatta.org/misc/list.jpg

The later is "screenshot" with testcode and results side-by-side. Tested
against Dinkumware's implementation. The STLPort 4.5.1020 (?) was twice as
fast as the Dinkumware, but still slower than the list.hpp implementation.
I'm perfectly aware that I am not yet throwing exceptions where should, and
not doing write to temporaries before assignment where appropriate for
thread safety, etc.. so my implementation isn't exception or threading safe.
Currently I am not using the allocator object, since it's redundant for this
implementation, but I'm still keeping it as template argument for
compatibility's sake.

I know the code is horrible mess, but my goal is to improve it to learn
better: I'm finally going to drop the custom containers from Open Source
library I have been maintaining the last decade (the library has been OS
only for the past two years).


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: someone@microsoft.com ("wogston")
Date: Sun, 26 Oct 2003 19:29:01 +0000 (UTC)
Raw View
Greets. I don't quite find this from the documentation on the net, and I
don't have the ANSI documentation.

Does std::list  ::assign() and ::insert() support copying from the same
object? Example:

std::list<int> v;
for ( int i=0; i<10; ++i )
  v.push_back(i);

std::list<int>::iterator itr = v.begin();
v.insert( itr, v.begin(), v.end() );

.. is this defined, or undefined? I'm assuming it is defined, because online
documentation such as Dinkumware's and MSDN don't say anything about any
limitations, but want to be sure. Apologies if this is a stupid question.

-x


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: someone@microsoft.com ("wogston")
Date: Sun, 26 Oct 2003 23:14:34 +0000 (UTC)
Raw View
> .. is this defined, or undefined? I'm assuming it is defined, because
online
> documentation such as Dinkumware's and MSDN don't say anything about any
> limitations, but want to be sure. Apologies if this is a stupid question.

Apologies for stupid question, when I realized the post didn't show up
promptly I understood this group is moderated! Anyway, why I was asking, was
because I thought the self-assignment case would be prohibitively expensive
to implement.

But after some thinking (I didn't cheat and look at Dinkumware, RogueWave,
STLPort, etc.. honest!), figured way to do it efficiently. It took about 5
minutes of my time, and already wasted too much of your time with this
silliness. Here's my solution:

First, the ::assign(iterator first, iterator last)

(apologies for slightly incorrect parameters if they are not 100% precise,
just want to present the idea)

1. erase( begin(),first )
2. attach the sequence between first and last to begin
3. erase( last,end() )

That's just pseudo, have to in the implementation ofcourse make sure the
iterators are valid through the process (so treat above only as pseudo).. so
I figured how that can be done fast.

Then the ::insert(iterator i, const_iterator first, const_iterator last)

In case of self-assignment, merely construct a temporary sequence and then
insert it before i. Implementation again has to make sure iterators are
valid through the implementation.

I detect self-assignment by storing "this" pointer for the container in the
linked-list node. (node is internal presentation of the data, iterator and
reverse_iterator are only front-ends), for instance, this is how ::begin()
looks for me:

iterator begin() {
    return iterator(this,m_begin.m_next); }

And then detect the self-assignment like this:

if ( i.container() == this ) { ...

I am such an idiot, 100% apologies, I was just implementing std::list as
mental exercise and read only online MSDN and Dinkumware documentation (like
said in original post, don't have the ANSI specs :(

So apologies for wasting everyone's time with so obvious matter, should have
thought 5 minutes longer before posting. I realize now I was a total retard.
:(


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]