Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment

169 views
Skip to first unread message

Ai Azuma

unread,
Nov 2, 2011, 2:16:55 PM11/2/11
to
`std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment'
(hereafter, abbreviated as POCMA) is defined as `std::false_type',
and it unduly imposes a burden on users.

`std::allocator_traits' class template is not explicitly specialized
for the default allocator (`std::allocator' class template),
and `std::allocator' does not have the nested typedef named
`propagate_on_container_move_assignment'.
Thus, POCMA is specified to be `std::false_type'.

However, in my humble opinion, nothing seems to prevent POCMA from
being defined as `std::true_type'.
No object of type `std::allocator<T>' has any object-specific state,
and all objects always compare equal each other.
Therefore, the move assignment operator of `std::allocator'
with a "do-nothing" implementation would meet the requirement for
POCMA to become `std::true_type'.
Actually, the implicitly defined copy assignment operator can also
function as the move one.

This means that a practical problem may arise in a specific context.
> From (23.2.1/14) and (Table 99), I conclude that the value type of
allocator-aware containers
with the default allocator type is required to be MoveInsertable and
MoveAssignable
when invoking the move assignment operator because POCMA is specified
as `std::false_type'.
However, I'm not convinced of this at all because it is at variance
with the model in my mind.
Such requirements are essentially unnecessary in the move assignment
operator
because allocator-aware containers with the default allocator type
only have to
swap the ownership of their resources in the move assignment operator.
I think that the problem here boils down to the wrong specification of
POCMA.

In addition, suppose that I am the author of an allocator-aware
container.
How can I implement the move assignment operator of that container as
efficient as possible?
Should I specialize the move assignment operator solely for the
default allocator type?
It is stupid.
If POCMA is defined as `std::true_type',
compile-time dispatch on the value of
`propagate_on_container_move_assignment'
would be enough to implement an efficient move assignment
and subsume the case of the default allocator type.

I would like to request either of the following changes;

i) adding the nested typedef like
`typedef std::true_type propagate_on_container_move_assignment;'
in the definition of std::allocator class template

ii) adding the explicit partial specialization of
`std::allocator_traits' class template
for `std::allocator' class template, in which POCMA is specified
as `std::true_type'.

I would like to hear from experts. Thank you in advance for your help.


--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Pablo Halpern

unread,
Nov 3, 2011, 8:10:19 PM11/3/11
to
Hello Ai,

On Nov 2, 2:16 pm, Ai Azuma<ai.az...@gmail.com> wrote:
> `std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment'
> (hereafter, abbreviated as POCMA) is defined as `std::false_type',
> and it unduly imposes a burden on users.
>
> `std::allocator_traits' class template is not explicitly specialized
> for the default allocator (`std::allocator' class template),
> and `std::allocator' does not have the nested typedef named
> `propagate_on_container_move_assignment'.
> Thus, POCMA is specified to be `std::false_type'.
>
> However, in my humble opinion, nothing seems to prevent POCMA from
> being defined as `std::true_type'.
> No object of type `std::allocator<T>' has any object-specific state,
> and all objects always compare equal each other.
> Therefore, the move assignment operator of `std::allocator'
> with a "do-nothing" implementation would meet the requirement for
> POCMA to become `std::true_type'.
> Actually, the implicitly defined copy assignment operator can also
> function as the move one.

The POCMA trait has little to do with the movability of the allocator
(most allocators are movable whether POCMA is true or false) and
everything to do with whether a container that uses that allocator
should re-assign its allocator on move assignment. For most stateful
allocators, the answer is "no" because there is a well-established
invariant that the allocator used at construction never changes
throughout the lifetime of the container. Setting POCMA to true
breaks this invariant, which is why it is not the default.

For stateless allocators, such as std::allocator, it should not matter
semantically whether POCMA is true or false. All allocators of that
type are equal and the containers are explicitly required to perform
an O(1) move assignment (actually O(N) because of destructor calls)
when the allocators compare equal, regardless of the value of POCMA.

> This means that a practical problem may arise in a specific context.> From (23.2.1/14) and (Table 99), I conclude that the value type of
>
> allocator-aware containers
> with the default allocator type is required to be MoveInsertable and
> MoveAssignable
> when invoking the move assignment operator because POCMA is specified
> as `std::false_type'.
> However, I'm not convinced of this at all because it is at variance
> with the model in my mind.
> Such requirements are essentially unnecessary in the move assignment
> operator
> because allocator-aware containers with the default allocator type
> only have to
> swap the ownership of their resources in the move assignment operator.
> I think that the problem here boils down to the wrong specification of
> POCMA.

OK, I see your point here. We overlooked an additional requirement
imposed by having POCMA be false. This is a real issue -- and
possibly could be considered a defect.

> In addition, suppose that I am the author of an allocator-aware
> container.
> How can I implement the move assignment operator of that container as
> efficient as possible?
> Should I specialize the move assignment operator solely for the
> default allocator type?

Yes, as a work-around, if you don't want to impose the extra
requirement. Consider, however, your intended audience: will your
users really expect move-assignment to work quickly for elements that
are not MoveInsertable and MoveAssignable? Remember that
MoveInsertable and MoveAssignable do not imply speed -- move
operations can be implemented as copy operations (and will default as
such if not provided explicitly. Of course, these operations will not
actually be called when performing a move assignment of your
container, but is it likely that they will be absent?

> It is stupid.

Please don't say that. It hurts our feelings :-)

> If POCMA is defined as `std::true_type',
> compile-time dispatch on the value of
> `propagate_on_container_move_assignment'
> would be enough to implement an efficient move assignment
> and subsume the case of the default allocator type.

True, but you should also be checking for equal allocators, which will
also subsume the case of the default allocator type. The efficiency
argument doesn't change, which is why we did not put a lot of thought
into whether the default allocator should have POCMA set or not. (We
overlooked the requirements issue and did nothing on the theory of
minimal change.)

> I would like to request either of the following changes;
>
> i) adding the nested typedef like
> `typedef std::true_type propagate_on_container_move_assignment;'
> in the definition of std::allocator class template
>
> ii) adding the explicit partial specialization of
> `std::allocator_traits' class template
> for `std::allocator' class template, in which POCMA is specified
> as `std::true_type'.

This is a reasonable request. I think that (i) is the simpler
approach. Please do me a favor and write this up as an issue having
the following parts:

1. Affected section of the standard
2. Description of the problem (focus on the unneeded requirements on
client code)
3. Proposed resolution (you can pick one or both)

Here is a link to an existing issue that you can model yours after
(but don't worry about the details of formatting):
http://lwg.github.com/issues/lwg-active.html#2052

Either post this issue here or email it to me directly. I will submit
it to the active issues list.

Thanks,
-Pablo

Ai Azuma

unread,
Nov 8, 2011, 2:32:10 PM11/8/11
to
Hi Pablo,

On Nov 4, 9:10 am, Pablo Halpern<phalp...@halpernwightsoftware.com>
wrote:
> The POCMA trait has little to do with the movability of the allocator
(snip)
> when the allocators compare equal, regardless of the value of POCMA.

I totally agree with you on that.

> Yes, as a work-around, if you don't want to impose the extra
(snip)
> container, but is it likely that they will be absent?

I see. I understand that my "efficiency argument" does nothing
but sidetracks the discussion.
I should have focused only on the requirement argument.

> Please don't say that. It hurts our feelings :-)

I'm really sorry to use the inappropriate words hurting your feelings.
I just wanted to point out the problem and never intended
to blame the work concerned with the standardization.
I always respect the hard work of the standardization.

> True, but you should also be checking for equal allocators, which will
> also subsume the case of the default allocator type. The efficiency
> argument doesn't change, which is why we did not put a lot of thought
> into whether the default allocator should have POCMA set or not. (We
> overlooked the requirements issue and did nothing on the theory of
> minimal change.)

Sorry for digressing from the main topic,
but I can't see any reason why equality check is necessary here.
When POCMA is true, the ownership of the internal resources
and the value of the allocator of the source container can be
unconditionally moved together to the target container, right?
Or am I missing something?

> Here is a link to an existing issue that you can model yours after
> (but don't worry about the details of formatting):
> http://lwg.github.com/issues/lwg-active.html#2052
>
> Either post this issue here or email it to me directly. I will submit
> it to the active issues list.

Thank you very much for your kind guide to write a defect report.
Now, I formally post the defect report below.
Please forward the following to the active issues list.

===== beginning of the defect report =====

Affected section of the standard:
20.6.9 [default.allocator]

Description of the problem:
`std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment::value'
is specified as `false', according to (20.6.9) and (20.6.8.1).
However, according to (23.2.1), this specification leads to
the unneeded requirements
(MoveInsertable and MoveAssignable of the value type)
on the move assignment operator of containers
with the default allocator.

Proposed resolution:
Either of the following two changes;

(1)adding the nested typedef like
`typedef std::true_type propagate_on_container_move_assignment;'
in the definition of std::allocator class template,

(2)adding the explicit partial specialization of
`std::allocator_traits' class template for `std::allocator'
class template, in which `propagate_on_container_move_assignment'
nested typedef is specified as `std::true_type'.

===== end of the defect report =====


Thank you.

Pablo Halpern

unread,
Dec 1, 2011, 5:02:08 PM12/1/11
to
This defect has been submitted as issue #2103 in the active issues
list. Thanks for writing it up.
-Pablo
> [ newsreader. If that fails, use mailto:std-cpp-sub...@vandevoorde.com ]
0 new messages