【问题标题】:C++: Move constructor not called, unless explicit casting is called [closed]C ++:不调用移动构造函数,除非调用显式转换[关闭]
【发布时间】:2020-10-16 19:19:05
【问题描述】:

我创建了一个类“ListElement”,它包含一个作为单个数据变量的类“MyClass”的实例,其中包含一个动态分配的数组。

  • 对于 ListElement,我创建了一个默认构造函数,它委托给一个初始化 MyClass 实例的右值构造函数。

  • 对于 MyClass,我创建了一个构造函数,它将其数组初始化为一个输入值(以及一个默认构造函数,它委托给上面的值为 0 的构造函数)。此外,我还包含了一个副本和一个移动构造函数。

然而,我很困惑,为什么不调用移动构造函数,除非数据类型被显式转换为 r 值引用,尽管它已经被这样传递(见下文)。

#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;
}

问题: 如果我为此行编写(参见 cmets),为什么会调用复制构造函数?

ListElement(MyClass<5>&& data) : data(data) {}

“data”是一个右值引用,但是移动构造函数只有在我明确地将它转换为这样的右值引用时才会被调用:

ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {}

非常感谢!

【问题讨论】:

  • 您应该对右值与对右值的引用进行一些研究。 data(data) 复制数据。 data { std::move(data) } 移动它。
  • 知道了,我更新了问题只是为了有一个问题。我怎样才能重新打开它以获得答案?
  • 重新打开它没什么用。它只会作为副本关闭。一种可能的欺骗目标stackoverflow.com/q/38406675/817643

标签: c++ c++11 templates copy-constructor move-constructor


【解决方案1】:

问题 1

因为data 不是右值。右值是无名data 是一个名称 ⇒ 不是一个右值。命名右值引用是绑定到右值的引用,但它们本身不是右值。

您的演员表是正确的,但不是通用的,也不是惯用的。标准库提供std::move 正是为此目的,使用它。

问题 2

我认为它应该在初始化列表中初始化为指向已分配数据的指针。一切都应该在初始化列表中初始化。如果这是不可能的,那么您的设计可能有问题。

MyClass(int value): a(new int[arrSize]) { ... }

当然,在实际代码中,您应该使用std::vectorstd::array

问题 3

大小不是动态定义的。它必须在编译时知道。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 2022-11-21
    • 1970-01-01
    • 2015-02-21
    相关资源
    最近更新 更多