#новичкам
Многие из вас подумали, что будет ошибка компиляции. В целом, логичная цепочка мыслей: ну как же можно мувнуть данные из константной ссылки? Она же неизменяема.
Но она все же неверная. Правильный ответ: на консоль выведется "copy ctor".
Копия? Мы же муваем!
Сейчас разберемся. Но для начало вспомним сам пример:
#include <iostream>
struct Test {
Test() = default;
Test(const Test &other) {
std::cout << "copy ctor" << std::endl;
}
Test(Test &&other) {
std::cout << "move ctor" << std::endl;
}
Test &operator=(const Test &other) = default;
Test &operator=(Test &&other) = default;
~Test() = default;
};
int main() {
Test test;
const Test &ref = test;
(void)std::move(ref);
auto emigma = std::move(ref);
}
На самом деле проблема в нейминге. Все вопросы к комитету. Это они имена всему плюсовому раздают.
std::move ничего не мувает. Она делает всего лишь static_cast. Но не просто каст к правой ссылке, это не совсем корректно. Посмотрим на реализацию std::move:
template <class T>
constexpr typename std::remove_reference<T>::type&& move(T&& t) noexcept {
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
Обратите внимание, что от типа отрезается любая ссылочность и только затем добавляется правоссылочность. Но константность-то никуда не уходит. По сути результирующий тип выражения std::move({константная левая ссылка}) это константная правая ссылка.
Чтобы это проверить, перейдем на cppinsights:
Test test;
const Test &ref = test;
using ExprType = decltype(std::move(ref));
// под капотом ExprType вот чему равен
using ExprType = const Test &&;
Так как мы просто кастуем к валидному типу, мув успешно отрабатывает, но строчка
(void)std::move(ref); не дает в консоли никакого вывода, потому что никаких новых объектов мы не создаем.Теперь про копирование. Вспомним правила приведения типов. const T&& может приводится только к const T&. То есть единственный конструктор, который может вызваться - это копирующий конструктор.
Интересная ситуация, конечно, что "перемещение" может приводить к копированию в плюсах. Но имеем, что имеем. Терпим и продолжаем грызть гранит С++.
Give a proper name. Stay cool.
#cppcore #template