У меня есть этот фрагмент кода, который я компилирую с помощью g++.exe -std=c++20
:
#include <iostream>
using namespace std;
class A {
public:
A() = delete;
A(int value) : value(value) {}
// A(auto &other) {
// cout << "Copy constructor called..." << endl;
// value = other.value;
// }
void operator=(const auto &other) = delete;
A(auto &&other) {
cout << "Move constructor called..." << endl;
value = other.value;
}
~A() { cout << "Destructor called..." << endl; }
friend ostream &operator<<(ostream &os, const A &a);
private:
int value;
};
ostream &operator<<(ostream &os, const A &a) {
os << a.value;
return os;
}
int main() {
A p1(2);
cout << "p1: " << p1 << endl;
A p2(p1);
cout << "p2: " << p2 << " p1: " << p1 << endl;
return 0;
}
Проблема, с которой я сталкиваюсь, заключается в том, что когда конструктор копирования комментируется, вывод
Move constructor called...
p2: 2 p1: 2
Destructor called...
Destructor called...
И если я раскомментирую конструктор копирования, вывод станет
p1: 2
Copy constructor called...
p2: 2 p1: 2
Destructor called...
Destructor called...
Мне интересно, почему компилятор просто не вызывает конструктор копирования по умолчанию (что происходит, когда я удаляю конструктор перемещения или изменяю его аргумент на const
, поэтому он не соответствует вызову).
В данном случае это не конструктор перемещения, а конструктор с универсальной ссылкой, поэтому он принимает как lvalue, так и rvalue. Если вы хотите ограничить его только значениями r, вам следует использовать явный тип:
A(A &&other) {
...
}
Мне интересно, почему компилятор просто не вызывает конструктор копирования по умолчанию (что происходит, когда я удаляю конструктор перемещения или изменяю его аргумент на
const
, поэтому он не соответствует вызову).
Имейте в виду, что этого не произойдет, потому что операции копирования неявно удаляются, если вы явно добавляете какую-либо операцию перемещения, поэтому вам придется добавить ее явно в этом случае:
A(const A &other) = default;
@user2565010 user2565010 auto&&
, а также T&&
- это просто несколько неудачный стиль для выражения правил вывода типов шаблонов. По сути, когда вы используете auto
, вы говорите «я хочу копию»; auto &
говорит «я хочу ссылку», и, наконец, auto &&
вы говорите «я хочу ссылку rvalue или ссылку lvalue, в зависимости от типа аргумента»
Является ли
A(auto&& other)
универсальной ссылкой, потому что auto может быть переведено вA(auto& && other)
, которое превращается вA(auto& other)
?