C++:不调用移动构造函数,除非调用显式转换
C++: Move constructor not called, unless explicit casting is called
我创建了一个 class、“ListElement”,它包含作为单个数据变量的 class“MyClass”实例,它包含一个动态分配的数组。
对于 ListElement,我创建了一个默认构造函数,它委托给一个初始化 MyClass 实例的右值构造函数。
对于 MyClass,我创建了一个构造函数,它将其数组初始化为一个输入值(以及一个默认构造函数,它使用值 0 委托给上面的构造函数)。此外,我还包含了一个副本和一个移动构造函数。
然而,我很困惑,为什么不调用移动构造函数,除非数据类型被显式转换为右值引用,尽管它已经这样传递了(见下文)。
#include <iostream>
template <int arrSize>
class MyClass {
private:
// Data
int* a;
public:
//Constructor
MyClass(int value){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize; ++i){
a[i] = value;
}
std::cout << "MyClass created!" << std::endl;
}
MyClass(): MyClass(0){}
//Copy Constructor
MyClass(const MyClass<arrSize>& other){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize;++i){
a[i] = other.a[i];
}
std::cout << "MyClass copied!" << std:: endl;
}
//Move Constructor
MyClass(MyClass<arrSize>&& other){
this->a = other.a;
other.a = nullptr;
std::cout << "MyClass moved!" << std::endl;
}
//Destructor
~MyClass(){
delete[] this->a;
std::cout << "MyClass deleted!" << std::endl;
}
};
class ListElement {
public:
//Constructors
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {} // QUESTION
ListElement(): ListElement(MyClass<5>(1)){}
private:
//Data
MyClass<5> data;
};
int main() {
ListElement myZeroListElement{};
return 0;
}
问题:
如果我为这一行写代码,为什么会调用复制构造函数(见评论)?
ListElement(MyClass<5>&& data) : data(data) {}
“数据”是一个右值引用,但是移动构造函数只有在我明确地将它转换为这样的右值引用时才会被调用:
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {}
非常感谢!
Question 1
因为 data
不是 右值。右值 nameless。 data
是一个名字 ⇒ 不是一个右值。命名右值引用是 绑定到 右值但它们本身不是右值的引用。
您的演员表是正确的,但不是通用的,也不是惯用的。标准库正是为此目的提供 std::move
,请使用它。
Question 2
我认为应该在初始化列表中将其初始化为指向已分配数据的指针。一切都应该在初始化列表中初始化。如果这是不可能的,那么可能是您的设计有问题。
MyClass(int value): a(new int[arrSize]) { ... }
当然在实际代码中你应该使用 std::vector
或 std::array
.
Question 3
大小不是动态定义的。必须在编译时知道。
我创建了一个 class、“ListElement”,它包含作为单个数据变量的 class“MyClass”实例,它包含一个动态分配的数组。
对于 ListElement,我创建了一个默认构造函数,它委托给一个初始化 MyClass 实例的右值构造函数。
对于 MyClass,我创建了一个构造函数,它将其数组初始化为一个输入值(以及一个默认构造函数,它使用值 0 委托给上面的构造函数)。此外,我还包含了一个副本和一个移动构造函数。
然而,我很困惑,为什么不调用移动构造函数,除非数据类型被显式转换为右值引用,尽管它已经这样传递了(见下文)。
#include <iostream>
template <int arrSize>
class MyClass {
private:
// Data
int* a;
public:
//Constructor
MyClass(int value){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize; ++i){
a[i] = value;
}
std::cout << "MyClass created!" << std::endl;
}
MyClass(): MyClass(0){}
//Copy Constructor
MyClass(const MyClass<arrSize>& other){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize;++i){
a[i] = other.a[i];
}
std::cout << "MyClass copied!" << std:: endl;
}
//Move Constructor
MyClass(MyClass<arrSize>&& other){
this->a = other.a;
other.a = nullptr;
std::cout << "MyClass moved!" << std::endl;
}
//Destructor
~MyClass(){
delete[] this->a;
std::cout << "MyClass deleted!" << std::endl;
}
};
class ListElement {
public:
//Constructors
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {} // QUESTION
ListElement(): ListElement(MyClass<5>(1)){}
private:
//Data
MyClass<5> data;
};
int main() {
ListElement myZeroListElement{};
return 0;
}
问题: 如果我为这一行写代码,为什么会调用复制构造函数(见评论)?
ListElement(MyClass<5>&& data) : data(data) {}
“数据”是一个右值引用,但是移动构造函数只有在我明确地将它转换为这样的右值引用时才会被调用:
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {}
非常感谢!
Question 1
因为 data
不是 右值。右值 nameless。 data
是一个名字 ⇒ 不是一个右值。命名右值引用是 绑定到 右值但它们本身不是右值的引用。
您的演员表是正确的,但不是通用的,也不是惯用的。标准库正是为此目的提供 std::move
,请使用它。
Question 2
我认为应该在初始化列表中将其初始化为指向已分配数据的指针。一切都应该在初始化列表中初始化。如果这是不可能的,那么可能是您的设计有问题。
MyClass(int value): a(new int[arrSize]) { ... }
当然在实际代码中你应该使用 std::vector
或 std::array
.
Question 3
大小不是动态定义的。必须在编译时知道。