[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-dev
Subject: Re: [cfe-dev] libc++ std::map self-assignment bug
From: Howard Hinnant <hhinnant () apple ! com>
Date: 2013-11-29 16:42:33
Message-ID: 32A64891-D1B3-4D23-97A8-3A8B6AAE6841 () apple ! com
[Download RAW message or body]
On Nov 29, 2013, at 2:50 AM, Kal <b17c0de@gmail.com> wrote:
> Am 29.11.13 04:17, schrieb Howard Hinnant:
> > On Nov 28, 2013, at 9:58 PM, Karen Shaeffer <shaeffer@neuralscape.com> wrote:
> >
> > > On Fri, Nov 29, 2013 at 02:19:44AM +0100, Kal wrote:
> > > > Hi Howard, etc,
> > > >
> > > > libc++3.4 (rc1/trunk) std::map doesn't support self-assignment for std <
> > > > c++11. The relevant code is:
> > > >
> > > > _LIBCPP_INLINE_VISIBILITY
> > > > map& operator=(const map& __m)
> > > > {
> > > > #if __cplusplus >= 201103L
> > > > __tree_ = __m.__tree_;
> > > > #else
> > > > __tree_.clear();
> > > > __tree_.value_comp() = __m.__tree_.value_comp();
> > > > __tree_.__copy_assign_alloc(__m.__tree_);
> > > > insert(__m.begin(), __m.end());
> > > > #endif
> > > > return *this;
> > > > }
> > > >
> > > > Maybe should be like:
> > > >
> > > > _LIBCPP_INLINE_VISIBILITY
> > > > map& operator=(const map& __m)
> > > > {
> > > > #if __cplusplus >= 201103L
> > > > __tree_ = __m.__tree_;
> > > > #else
> > > > if (this != &__m) {
> > > > __tree_.clear();
> > > > __tree_.value_comp() = __m.__tree_.value_comp();
> > > > __tree_.__copy_assign_alloc(__m.__tree_);
> > > > insert(__m.begin(), __m.end());
> > > > }
> > > > #endif
> > > > return *this;
> > > > }
> > > >
> > > > I see the same issue with unordered_map& operator=(const unordered_map&
> > > > __u).
> > > >
> > > > Thanks!
> > > > Kal
> > > --- end quoted text ---
> > >
> > > Hi Kal,
> > > I don't speak for Howard or anyone else. But my understanding is the stl \
> > > library generally doesn't perform checks like that with the goal of best \
> > > possible performance. I see a lot of code in stdlibc++ just like that.
> > Actually this does look like a bug to me (for __cplusplus < 201103L). I think \
> > Kal has the correct fix. A post-condition of copy assignment is that both lhs \
> > and rhs should be equivalent to the previous value of rhs. For move assignment \
> > this is not the case. But this is copy assignment.
> > Howard
> >
> Hi Howard,
> Thanks for the reply. Do you think a fix for this will be committed for
> the 3.4 release?
I don't know.
>
> Also could you explain why the special check for __cplusplus < 201103L
> is necessary at all. Both branches are doing almost the same thing
> (looking into the implementation of __tree). Is there some subtle
> difference in the standard that requires a different implementation here?
C++11 introduces the possibility of recycling nodes of [multi]map under the copy \
assignment operator by pushing the requirements on [multi]map::value_type down to the \
key_type and mapped_type (23.2.4 [associative.reqmts]/p7). To actually implement \
this optimization I used new C++11 language features of union, which do not compile \
when -std=c++03.
In C++11, using libc++, if two equal sized map<int, int> are assigned, there are zero \
trips to the heap. The nodes in the lhs are assigned new values, and rebalancing \
takes place as necessary. In C++03, the lhs is first clear()'d, and then one does an \
insert for every value in the rhs.
Same design (and bug as you note) in unordered_[multi]map.
Howard
_______________________________________________
cfe-dev mailing list
cfe-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic