3

Difference between MoveInsertable and CopyInsertable? suggests that a type T is MoveInsertable if the allocator can construct an object of type T from an rvalue of the same type. However, MoveConstructible also requires T to be constructible from an rvalue of the same type. Then, what's the difference between them?

cpplearner
  • 13,776
  • 2
  • 47
  • 72

1 Answers1

5

There's no meaningful difference in the case of default allocator (std::allocator<T>). For unspecialized std::allocator<T>, one can treat MoveInsertable as a synonym for move-constructible.

However, the difference manifests if an allocator has member construct, and that member does different thing from the default allocator_traits<A>::construct. A typical example is std::pmr::polymorphic_allocator, which performs the so-called "uses-allocator construction":

  • if std::uses_allocator_v<T, polymorphic_allocator<T>> is false, the behavior is same as allocator_traits<A>::construct;
  • if std::uses_allocator_v<T, polymorphic_allocator<T>> is true, the allocator is passed as additional argument to the constructor.

Therefore, one can invent a type that is MoveInsertable with polymorphic allocator, but not MoveConstructible, or vice versa. (More realistically, one can create a type whose move-insertion has different effect from move-construction.)

#include <memory>
#include <memory_resource>
#include <vector>

struct evil {
    using allocator_type =
        std::pmr::polymorphic_allocator<evil>; // make std::uses_allocator return true

    evil();
    evil(evil&&) = delete; // not move constructible
    evil(evil&&, const allocator_type&);
};

int main() {
    evil a;
    evil b = std::move(a); // Error: evil is not MoveConstructible
    std::pmr::vector<evil> v;
    v.push_back(std::move(a)); // OK, evil is MoveInsertable
}
cpplearner
  • 13,776
  • 2
  • 47
  • 72