移动构造与析构顺序

为了理解std::move在干什么,写了一个小例子研究一下


std::move(obj1) 不会真的移动数据,它只是把 obj1 转成右值引用(MyClass&& obj1),让编译器选择调用 MyClass 的移动构造函数。

移动构造函数会接管资源的指针(例如堆内存地址)而不是复制数据,这样速度更快。

移动后,obj1 处于有效但未指定的状态(通常是空的,但不要依赖它的具体内容)。

#include <iostream>
#include <utility>
#include <string>

class MyClass {
private:
    int* data;
    std::string name; // 记录对象名字,方便输出

public:
    MyClass(int value, std::string n)
        : data(new int(value)), name(std::move(n)) {
        std::cout << name << " 构造函数: 分配数据 " << *data << "\n";
    }

    // 拷贝构造
    MyClass(const MyClass& other)
        : data(new int(*other.data)), name(other.name + "_copy") {
        std::cout << name << " 拷贝构造: 复制数据 " << *data << "\n";
    }

    // 移动构造
    MyClass(MyClass&& other) noexcept
        : data(other.data), name(other.name + "_moved") {
        other.data = nullptr;
        std::cout << name << " 移动构造: 接管数据\n";
    }

    ~MyClass() {
        if (data) {
            std::cout << name << " 析构函数: 释放数据 " << *data << "\n";
            delete data;
        } else {
            std::cout << name << " 析构函数: 空数据,无需释放\n";
        }
    }
};

int main() {
    MyClass obj1(42, "obj1");            // 第一个创建
    MyClass obj2 = obj1;                 // 第二个创建(拷贝构造)
    MyClass obj3 = std::move(obj1);      // 第三个创建(移动构造)
    return 0;
}

运行示例输出

obj1 构造函数: 分配数据 42      
obj1_copy 拷贝构造: 复制数据 42 
obj1_moved 移动构造: 接管数据   
obj1_moved 析构函数: 释放数据 42
obj1_copy 析构函数: 释放数据 42 
obj1 析构函数: 空数据,无需释放 

重点说明

  1. 拷贝构造(MyClass(const MyClass&))
  • 分配新内存并复制数据。
  • 比较慢,因为要分配+复制。
  1. 移动构造(MyClass(MyClass&&))
  • 接管旧对象的指针,不分配新内存。
  • 原对象的指针置空,防止析构时重复释放。
  • 快很多,尤其是资源很大时(例如大数组、文件句柄、网络连接等)。
  1. std::move 不是真的“移动”,它只是把左值强制转成右值引用,触发调用移动构造函数。

在这个例子里,obj1obj2obj3main 函数的局部变量,它们的析构顺序遵循 C++ 的作用域规则——后创建的对象先析构(栈是后进先出 LIFO)。

posted @ 2025-08-14 12:13  雨天尊  阅读(14)  评论(0)    收藏  举报