关于Move构造函数的临时对象(C++)

2g32fytz  于 2023-04-13  发布在  其他
关注(0)|答案(1)|浏览(144)

假设我有一个类,即class MyClass,我已经为它实现了一个Move构造函数MyClass::MyClass(MyClass &&rhs):ptr(rhs.ptr) {rhs.ptr=nullptr;}。此外,class MyClass包含一个成员属性,它是一个指向整数的指针:int* ptr;。如果我声明一个包含class MyClass对象的vector,IOW std::vector<MyClass> vec;,并使用带有r值的std::vector::push_back方法,使得:

std::vector<MyClass> vec;
vec.push_back(MyClass {5});

首先调用class MyClass的构造函数,为MyClass {5}创建一个对象。然后调用Move构造函数,我们说我们窃取了“临时”对象的资源。但是,我不知道我们到底从哪个对象窃取了资源。当调用Move构造函数时,我认为一个暂时的物体(即x值表达式)被构造,我们从这个对象中窃取资源,并将它们交给我们用class MyClass的构造函数创建的第一个对象。然后,一旦Move构造函数超出作用域,这个x值就会被析构,最后我们将包含被盗数据的对象push_back放入vector中。简而言之,我们在内存中“移动”资源。
如果在Move构造函数中创建了一个临时对象,那么Move构造函数相对于Copy构造函数的优势是什么?在Move构造函数的情况下,程序创建了两个对象,其中一个是临时的,并且在短时间内被析构。在Copy构造函数的情况下,程序创建了两个对象,其中一个对象在复制到vector中时再次被销毁(我从构造函数和析构函数被调用的次数推断出这些)。
可能是我误解了Move和Copy构造函数的复制和构造过程背后的过程,但是,我无法从SO的其他问题中得到任何答案。他们只是说对象是“创建”,“复制”和“移动”,但是,我想知道这些过程的细节。

mtb9vblg

mtb9vblg1#

你不明白的可能是vector是如何使用你的临时对象进行优化的。让我们做一组测试。

struct Vector {
  MyClass *t;
  int size = 0;
  Vector() { t = new MyClass[4]; }
  ~Vector() { delete[] t; }
  void push_back(MyClass &&myClass) {
    t[size] = std::move(myClass);
    size++;
  }
  void push_back(const MyClass &myClass) {
    t[size] = myClass;
    size++;
  }
};

然后我们将打印信息添加到MyClass构造函数中。

struct MyClass {
  MyClass() { printf("I'm Constructor\n"); }
  MyClass &operator=(MyClass &&myClass) {
    printf("I'm move assignments Constructor\n");
    return *this;
  }
  MyClass &operator=(const MyClass &myClass) {
    printf("I'm copy assignments Constructor\n");
    return *this;
  }
};

然后我们测试它。

Vector vector;
printf("push_back()\n");
MyClass myClass;
vector.push_back(myClass);
vector.push_back(MyClass());
vector.push_back(std::move(myClass));

结果可以如下:

...  
push_back()      
I'm Constructor
I'm copy assignments Constructor
I'm Constructor
I'm move assignments Constructor
I'm move assignments Constructor

从结果中可以看到,临时对象只是简单地用移动赋值来代替复制赋值,但是这里并不清楚移动是否优于复制,所以我们在MyClass中添加一个动态分配的指针p,如果它很大,那么我们就可以直接通过移动赋值中的这个-〉p=p来窃取临时对象分配的内存,这样就减少了这个过程中的内存分配开销。

相关问题