c++ type trait to say "trivially movable" - examples of
Asked Answered
C

2

7

I would define "trivially movable" by

Calling the move constructor (or the move assignment operator) is equivalent to memcpy the bytes to the new destination and not calling the destructor on the moved-from object.

For instance, if you know that this property holds, you can use realloc to resize a std::vector or a memory pool.

Types failing this would typically have pointers to their contents that needs to be updated by the move constructor/assignment operator.

There is no such type traits in the standard that I can find. I am wondering whether this already has a (better) name, whether it's been discussed and whether there are some libraries making use of such a trait.

Edit 1:

From the first few comments, std::is_trivially_move_constructible and std::is_trivially_move_assignable are not equivalent to what I am looking for. I believe they would give true for types containing pointers to themselves, since reading your own member seems to fall under "trivial" operation.

Edit 2:

When properly implemented, types which point to themselves won't be trivially_move_constructible or move_assignable because the move ctor / move assignment operator are not trivial anymore. Though, we ought to be able to say that unique_ptr can be safely copied to a new location provided we don't call its destructor.

Clichy answered 18/8, 2017 at 3:14 Comment(9)
std::is_trivially_move_constructible and std::is_trivially_move_assignable seem to be what you're afterPirn
Doesn't std::is_trivially_copyable() already cover what you want?Spiel
The problem is that this concept isn't quite the same as that expressed by the similarly-named functions in the standard, especially the part about skipping the destructor.Fanfani
According to cplusplus.com "A trivially move constructible class is a class (defined with class, struct or union) that: uses the implicitly defined move constructor. has no virtual members. its base class and non-static data members (if any) are themselves also trivially move constructible types." Meaning that unique_ptr would not match.Clichy
Trivially copyable seems to fit. The precondition of memcpy is that the type is trivially copyable, your example of self referencing objects are not.Chloride
If a struct that hiolds a pointer to one of its member, it is definitely not trivialy move contructible, nor trivially move assignable, since the pointer does need to be updated. Now, the real question is, does the std detect this condition correctly, and if so, how?Turney
Passer By, unique_ptr is not trivially copyable because you would destroy the object twice. Though it would be "trivially movable".Clichy
@Clichy What move operations did you have in mind other than move/assign or move/contruct ? Thats is not clear.Turney
Michaël, bitwise move, probably somewhat similar to Rust destructive move. To move an object from p1 to p2 I copy the bytes and I don't call the destructor. Something that would make it easy to implement a memory pool for a type matching the requirement.Clichy
M
7

I think what you need is std::is_trivially_relocatable from proposal P1144. Unfortunately the proposal didn't make it into C++20, so we shouldn't expect it before 2023. Which is sad, because this type trait would enable great optimizations for std::vector and similar types.

UPD. Nope, not C++23 either. Quoting the author of P1144: “definitely not C++23, I bet not C++26, quite possibly not ever”.

Mucronate answered 30/10, 2020 at 10:9 Comment(0)
M
1

Well, this got me thinking... It is very important to overload type traits of structs that hold a pointer to themselves.

The following code demonstrates how fast a bug can creep in code, when type_traits are not defined properly.

#include <memory>
#include <type_traits>

struct A
{
    int a;
    int b;
    int* p{&a};
};

int main()
{
   auto p = std::make_unique<A>();
   A a = std::move(*p.get());  // gets moved here, a.p is dangling.

   return  std::is_move_assignable<A>::value;  // <-- yet, this returns true.
}
Meetly answered 18/8, 2017 at 4:58 Comment(3)
I guess that A is incorrect, it is not movable as such. It probably should delete it's move ctor and move assignement.Clichy
Yes. This means that "reading your own member" does not and should not fall under "trivial" operation...Turney
Actually not. If the type is implemented properly, it should override the move constructor and it would not be trivial anymore (trying with adding a proper move ctor above and is_trivially_move_constructible).Clichy

© 2022 - 2024 — McMap. All rights reserved.