[prev in list] [next in list] [prev in thread] [next in thread] 

List:       boost-users
Subject:    Re: [Boost-users] [assign][ptr_container] Exception safety of ptr_list_of, ptr_push_back, ptr_map_in
From:       Gavin Lambert <gavinl () compacsort ! com>
Date:       2014-09-25 0:47:32
Message-ID: lvvon5$rhi$1 () ger ! gmane ! org
[Download RAW message or body]

On 24/09/2014 21:52, Aaron Levy wrote:
> Yes I saw that the documentation says these are exception safe and
understandably the arguments are forwarded to the constructors. I was
just trying to understand the scenarios under which code like the
example below cause exception-safety issues.
>
> boost::ptr_vector<Foo> vec;
> push_back(vec)(new Foo)(new Foo);
>
> My reasoning was that the nth "new Foo" gets evaluated after the n-1
"new Foo" expressions which by then are already part of the container.

That is not correct.  The compiler is free to evaluate the independent 
subexpressions in any order; it is only constrained by dependent 
expressions.  For example, the below code is a valid rewrite of the 
above by the compiler internals:

boost::ptr_vector<Foo> vec;
Foo *tmp2 = new Foo;
auto tmp3 = push_back(vec);
Foo *tmp1 = new Foo;
auto tmp4 = tmp3(tmp1);
tmp4(tmp2);

In particular note that if the second "new Foo" (to tmp1) throws -- 
which is possible due to out-of-memory even if for no other reason -- 
then the pointer in tmp2 will be leaked, as it hasn't yet been assigned 
to the container.  The same can occur if push_back or if tmp3() throw.

The compiler is free to allocate tmp1 and tmp2 in any order; the only 
constraints are:

1. It must call their constructors after the constructor of vec is called.
2. It must create tmp1 before it can call tmp3 to create tmp4.
3. It must create tmp2 before it can call tmp4.

Similarly if there were any parameters being passed to the Foo 
constructor (whether using this method or using constructor forwarding), 
temporary values for these could be created in any order -- not just out 
of parameter order but also not in the order of constructing the objects 
they're being passed to.

It's the same principle as this:

   f(a(), b(), c(), d());

In the above, the compiler can call a,b,c,d in any order.  The only 
constraint is that it must call all four of them before it can call f.


_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic