Why are a pair or tuple of TrivialTypes not themselves TrivialTypes?

544 views
Skip to first unread message

Matt Newport

unread,
Sep 15, 2014, 7:09:04 PM9/15/14
to std-dis...@isocpp.org
It seems desirable for a pair or tuple containing only TrivialTypes (types for which is_trivial<T>::value is true) to also be a TrivialType but the standard doesn't seem to require this and it doesn't seem to be the case in the implementations I've tested (MSVC 2013 and clang with libc++). 

In both implementations the default constructor is explicitly defined rather than explicitly defaulted with "= default". It seems that requiring the default constructors to be explicitly defaulted would ensure that a pair or tuple of TrivialTypes was also a TrivialType. Is there a reason the standard doesn't specify this? Experimenting with clang suggests there might be issues with allowing a constexpr default constructor for pair if the default constructor was required to be explicitly defaulted but I'm not sure if that is the reason it is not implemented that way.

The reason this came up is I was looking at when an std::vector type container is able to optimize certain operations to use memcopy or memmove rather than calling constructors and destructors and noticing that a vector<pair<int, int>> does not use this optimization where a vector<int> does.

Matt.

Matheus Izvekov

unread,
Sep 15, 2014, 7:22:33 PM9/15/14
to std-dis...@isocpp.org
Vector and other containers should condition those memcpy optimizations on whether the underlying type is trivially copyable, not whether it's trivial.

Matt Newport

unread,
Sep 15, 2014, 7:34:29 PM9/15/14
to std-dis...@isocpp.org
Thanks, you're right. This raises the question of why neither type is_trivially_copyable either on the implementations I'm testing then. Presumably because they don't explicitly default the copy or move assignment operators? What would be required to ensure that pair and tuple are TriviallyCopyableTypes if all of their members are TriviallyCopyableTypes?

Matt Newport

unread,
Sep 15, 2014, 7:41:42 PM9/15/14
to std-dis...@isocpp.org
Actually, with further testing it seems is_trivially_copyable<pair<int, float>>::value is true for MSVC 2013 but is_trivially_copyable<tuple<int, float>>::value is false. For clang with libcpp neither pair<int, float> nor tuple<int, float> are trivially copyable. Maybe this can be considered an implementation quality issue.

Matheus Izvekov

unread,
Sep 15, 2014, 7:41:49 PM9/15/14
to std-dis...@isocpp.org
On Monday, September 15, 2014 8:34:29 PM UTC-3, Matt Newport wrote:
Thanks, you're right. This raises the question of why neither type is_trivially_copyable either on the implementations I'm testing then. Presumably because they don't explicitly default the copy or move assignment operators? What would be required to ensure that pair and tuple are TriviallyCopyableTypes if all of their members are TriviallyCopyableTypes?




The only trivially copyable types are scalar types, trivially copyable classes, and arrays of such types/classes (possibly const-qualified, but not volatile-qualified).

A trivially copyable class is a class that

1. Has no non-trivial copy constructors (this also requires no virtual functions or virtual bases)
2. Has no non-trivial move constructors
3. Has no non-trivial copy assignment operators
4. Has no non-trivial move assignment operators
5. Has a trivial destructor 

The above is taken from cppreference, which in turn is taken from the standard text.

In another thread, we have been discussing that is_trivially_copyable is fundamentally broken because it mixes two different concepts, and part of the solution involves the user being able to explicitly specify whether a memcpy copy of a class preserves the value of it's original. Not sure if that would help you in your situation though.

Gabriel Dos Reis

unread,
Sep 15, 2014, 7:45:23 PM9/15/14
to std-dis...@isocpp.org
Matt Newport <matt.t...@gmail.com> writes:

| It seems desirable for a pair or tuple containing only TrivialTypes
| (types for which is_trivial<T>::value is true) to also be a
| TrivialType but the standard doesn't seem to require this and it
| doesn't seem to be the case in the implementations I've tested (MSVC
| 2013 and clang with libc++). 

when you have at least 8 ways of constructing a pair -- conceptually a
simple pair of data -- I wouldn't expect the resulting type to be
trivial no matter how trivial its individual components are. For
running those 8 constructors must be non-trivial ;-)

Matt Newport

unread,
Sep 15, 2014, 7:52:00 PM9/15/14
to std-dis...@isocpp.org, g...@axiomatics.org
It seems like it would be desirable for a vector<pair<int, int>> to be as efficient as a vector<MyPairOfInts> though (where MyPairOfInts is a struct that behaves the same as pair<int, int> but is_trivially_copyable). If it's not possible to achieve that given the current wording of the standard I'm curious why not :)

And if it is achievable under the current standard, it would be nice if common implementations managed it. All of this assuming that there is a measurable performance benefit of course, I haven't got benchmark numbers comparing them yet.

Matheus Izvekov

unread,
Sep 15, 2014, 8:00:43 PM9/15/14
to std-dis...@isocpp.org, g...@axiomatics.org
On Monday, September 15, 2014 8:52:00 PM UTC-3, Matt Newport wrote:
It seems like it would be desirable for a vector<pair<int, int>> to be as efficient as a vector<MyPairOfInts> though (where MyPairOfInts is a struct that behaves the same as pair<int, int> but is_trivially_copyable). If it's not possible to achieve that given the current wording of the standard I'm curious why not :)

And if it is achievable under the current standard, it would be nice if common implementations managed it. All of this assuming that there is a measurable performance benefit of course, I haven't got benchmark numbers comparing them yet.


Agreed. I'd wager the problem has something to do with those classes declaring any non-trivial copy/move constructors/assignment operators. It might be a QoI thing rather than mandated by the standard.

Gabriel Dos Reis

unread,
Sep 15, 2014, 8:33:09 PM9/15/14
to Matt Newport, std-dis...@isocpp.org
Matt Newport <matt.t...@gmail.com> writes:

| And if it is achievable under the current standard, it would be nice
| if common implementations managed it. All of this assuming that there
| is a measurable performance benefit of course, I haven't got benchmark
| numbers comparing them yet.

Numbers tend to be effective at persuading implementors.

-- Gaby
Reply all
Reply to author
Forward
0 new messages