Topic: Container swap and iterator invalidation or not?


Author: INVALID_use_webform@vecerina.com ("Ivan Vecerina")
Date: Wed, 12 Apr 2006 16:40:42 GMT
Raw View
Hi,
I'm recovering from the pain of a painful debugging session with
an error appearing only in release build...

Here's a sample triggering the problem:


#include <list>
#include <string>

typedef std::string Foo;
typedef std::list<Foo> Foos;
typedef Foos::iterator FooI;

FooI generateListAndReturnOne( Foos& out_foos )
{
   Foos temp;
   temp.push_front("a");  //... could throw...
   temp.push_back("b");
   FooI result = temp.begin();
   ++result;

   out_foos.swap( temp ); // we are now safe -> export result

   //** note that result was created before the swap.
   // Is it now a valid iterator into out_foos,
   //   or has it been invalidated ??
   return result;
}

int main()
{
   Foos foos;
   FooI pos = generateListAndReturnOne( foos );
   bool isFirst = (pos==foos.begin());   // Undefined Behavior ??
   return 0;
}


In debug mode, the STL implementation of VS2005 accepts the above
without complaint (in spite of intensive runtime checks).
But in release mode, where this STL implementation still chooses
to still perform some runtime checks by default, it will trigger
some obscure error... which has been a pain to track down.

I think that this issue has been debated before, and I wonder now:
if this is actually undefined behavior or not, by the latest
interpretation/revision of the standard ?
And where do we see the standard is going with such matters ?


Thank you,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form



---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 13 Apr 2006 10:35:38 CST
Raw View
"Ivan Vecerina" wrote:
> Hi,
> I'm recovering from the pain of a painful debugging session with
> an error appearing only in release build...
>
> Here's a sample triggering the problem:
>
>
> #include <list>
> #include <string>
>
> typedef std::string Foo;
> typedef std::list<Foo> Foos;
> typedef Foos::iterator FooI;
>
> FooI generateListAndReturnOne( Foos& out_foos )
> {
>    Foos temp;
>    temp.push_front("a");  //... could throw...
>    temp.push_back("b");
>    FooI result = temp.begin();
>    ++result;
>
>    out_foos.swap( temp ); // we are now safe -> export result
>
>    //** note that result was created before the swap.
>    // Is it now a valid iterator into out_foos,
>    //   or has it been invalidated ??
>    return result;
> }

According to 23.1p10, "no swap() function invalidates any references,
pointers, or iterators referring to the elements of the containers
being swapped."

The standard is less than clear about which container the references,
pointers, and iterators actually refer to after the swap. However, it
seems to me that for the most natural implementation, references,
pointers and iterators that originally referred to elements of the
first container will refer to the second container after the swap, and
vice versa.

However, if I'm wrong about that, the result your function returns
points to a container that will no longer exist after the function
returns. That would be undefined behavior.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: falk.tannhauser@crf.canon.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Fri, 14 Apr 2006 07:35:43 GMT
Raw View
Ivan Vecerina wrote:
> #include <list>
> #include <string>
>=20
> typedef std::string Foo;
> typedef std::list<Foo> Foos;
> typedef Foos::iterator FooI;
>=20
> FooI generateListAndReturnOne( Foos& out_foos )
> {
>    Foos temp;
>    temp.push_front("a");  //... could throw...
>    temp.push_back("b");
>    FooI result =3D temp.begin();
>    ++result;
>=20
>    out_foos.swap( temp ); // we are now safe -> export result
>=20
>    //** note that result was created before the swap.
>    // Is it now a valid iterator into out_foos,
>    //   or has it been invalidated ??

=A7 23.1/10 looks perfectly unambiguous to me:
   Unless otherwise specified (see 23.2.1.3 and 23.2.4.3)
   all container types defined in this clause meet the
   following additional requirements:
   [...]
   - no swap() function invalidates any references,
     pointers, or iterators referring to the elements
     of the containers being swapped.

The exceptions mentioned above concern deque and vector modifiers only.

>    return result;
> }
>=20
> int main()
> {
>    Foos foos;
>    FooI pos =3D generateListAndReturnOne( foos );
>    bool isFirst =3D (pos=3D=3Dfoos.begin());   // Undefined Behavior ??
>    return 0;
> }

Falk

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: INVALID_use_webform@vecerina.com ("Ivan Vecerina")
Date: Fri, 14 Apr 2006 07:38:58 GMT
Raw View
""Ivan Vecerina"" <INVALID_use_webform@vecerina.com> wrote in message=20
news:5749f$443d2a25$3e028af2$4952@news.hispeed.ch...
: I'm recovering from the pain of a painful debugging session with
: an error appearing only in release build...

I have since confirmed that this is a known issue in VS2005
  [http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?feedba=
ckId=3DFDBK47862]
And that container swap shall not invalidate iterators
(=A723.1/10 in my 1998 copy of the standard: <<< no swap() function
 invalidates any references, pointers, or iterators referring to
 the elements of the containers being swapped.>>> ),
except for std::string  (=A721.3/5), interestingly enough.

: I think that this issue has been debated before, and I wonder now:
: if this is actually undefined behavior or not, by the latest
: interpretation/revision of the standard ?
So the answer seems clear: container swap does not invalidate iterators.

: And where do we see the standard is going with such matters ?
I still wonder if the exception for std::string will remain,
but it is not a big concern for me anymore.

Thanks --Ivan
--=20
http://ivan.vecerina.com/contact/?subject=3DNG_POST <- email contact form




---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Fri, 14 Apr 2006 02:37:04 CST
Raw View
"Ivan Vecerina" a    crit :

> Hi,
> I'm recovering from the pain of a painful debugging session with
> an error appearing only in release build...
>
> Here's a sample triggering the problem:
>
>
> #include <list>
> #include <string>
>
> typedef std::string Foo;
> typedef std::list<Foo> Foos;
> typedef Foos::iterator FooI;
>
> FooI generateListAndReturnOne( Foos& out_foos )
> {
>    Foos temp;
>    temp.push_front("a");  //... could throw...
>    temp.push_back("b");
>    FooI result = temp.begin();
>    ++result;
>
>    out_foos.swap( temp ); // we are now safe -> export result
>
>    //** note that result was created before the swap.
>    // Is it now a valid iterator into out_foos,
>    //   or has it been invalidated ??
>    return result;
> }
>
> int main()
> {
>    Foos foos;
>    FooI pos = generateListAndReturnOne( foos );
>    bool isFirst = (pos==foos.begin());   // Undefined Behavior ??
>    return 0;
> }
>
>
> In debug mode, the STL implementation of VS2005 accepts the above
> without complaint (in spite of intensive runtime checks).
> But in release mode, where this STL implementation still chooses
> to still perform some runtime checks by default, it will trigger
> some obscure error... which has been a pain to track down.
>
> I think that this issue has been debated before, and I wonder now:
> if this is actually undefined behavior or not, by the latest
> interpretation/revision of the standard ?
> And where do we see the standard is going with such matters ?
>

I think it is valid, because of [lib.container.requirements], paragraph
10:
  --no swap() function invalidates any references, pointers,  or
itera-
    tors referring to the elements of the containers being swapped.


---
[ 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.comeaucomputing.com/csc/faq.html                      ]