Cpp 移动构造函数的问题

2022-06-19 22:37:48 +08:00
 woshichuanqilz

这个是我的代码, 按照移动构造函数的定义, 我先创建了一个对象 a, 这个对象强制使用 move 调用移动构造函数赋值给 b, 这个时候, a, b 里面的成员变量的地址 data 应该是一样的, 为什么我这里显示的不一样?

运行结果

Constructor is called for 10 000000950D2FF7F8 // addr Move Constructor for 10 000000950D2FF818 // addr Destructor is called for 10 Destructor is called for nullptr

// C++ program with declaring the
// move constructor
#include <iostream>
#include <vector>
using namespace std;

// Move Class
class Move {

public:

    int* data;
    // Constructor
    Move(int d)
    {
        // Declare object in the heap
        data = new int;
        *data = d;
        cout << "Constructor is called for "
            << d << endl;
    };

    // Copy Constructor
    Move(const Move& source)
        : Move{ *source.data }
    {

        // Copying the data by making
        // deep copy
        cout << "Copy Constructor is called -"
            << "Deep copy for "
            << *source.data
            << endl;
    }

    // Move Constructor
    Move(Move&& source)
        : data{ source.data }
    {

        cout << "Move Constructor for "
            << *source.data << endl;
        source.data = nullptr;
    }


    // Destructor
    ~Move()
    {
        if (data != nullptr)

            // If pointer is not pointing
            // to nullptr
            cout << "Destructor is called for "
            << *data << endl;
        else

            // If pointer is pointing
            // to nullptr
            cout << "Destructor is called"
            << " for nullptr "
            << endl;

        // Free up the memory assigned to
        // The data member of the object
        delete data;
    }
};

// Driver Code
int main()
{
    // Vector of Move Class
    //vector<Move> vec;

    //// Inserting Object of Move Class
    //vec.push_back(Move{ 10 });
    //vec.push_back(Move{ 20 });
    Move a(10);
    cout << &(a.data) << endl;
    Move b = move(a);
    cout << &(b.data) << endl;
    return 0;
}
1360 次点击
所在节点    程序员
14 条回复
codehz
2022-06-19 22:43:24 +08:00
移动构造没有移动对象本体——移动的是内部引用的其他资源
(然后如果用 vector 的话,可以 vector<Move> vec; vec.emplace(10); 来直接原地构造到对应位置去
codehz
2022-06-19 22:44:46 +08:00
打错,是 emplace_back
stein42
2022-06-19 22:45:46 +08:00
相同的应该是 a.data 和 b.data ,它们的类型是 int*。
而不是 &(a.data) 和 &(b.data),它们的类型是 int**。
wevsty
2022-06-19 22:49:50 +08:00
&(a.data) 代表的是 a 这个对象中的 data 成员所在的地址。
所以为什么 &(a.data) 要等于 &(b.data)?

移动构造并不是把原先的对象取一个不同名字的引用,你实现的移动构造函数只能保证 a.data = b.data 但是 a 和 b 仍然是两个独立的对象。
woshichuanqilz
2022-06-19 23:02:16 +08:00
@wevsty 那移动的意义在哪 这不和拷贝构造函数一样了吗?
woshichuanqilz
2022-06-19 23:03:45 +08:00
@codehz 这个我理解是移动构造函数最常见的情况, 就是 move 一个临时变量, 但是如果我强制调用 move 在一个声明的变量上给另一个, 似乎没有出现移动构造的效果
woshichuanqilz
2022-06-19 23:05:45 +08:00
@stein42 如果地址不相同的话说明复制了一份? 那么为什么叫移动, 不是和拷贝构造一样了
codehz
2022-06-19 23:10:25 +08:00
@woshichuanqilz
移动的意义就是可以表达不“深层次”复制内容的意图,而是转移原始对象的对引用资源到新的对象上(这个也得你自己实现,比如把原始对象里对应指针属性设置为 0 ,free 的时候就不会 double free 了)
stein42
2022-06-19 23:16:29 +08:00
C++ 是把对象和资源关联到一起,移动是移动关联的资源。
这里 Move 对象关联的资源就是 new 分配的内存,析构函数会释放这块内存(如果不为空的话)。
复制构造函数是新分配了一块内存,并把值复制过来。
移动构造函数是转移了资源,这里既 a 分配的内存转移给了 b 。
yanqiyu
2022-06-19 23:23:27 +08:00
@woshichuanqilz 移动的意思是 *data 这个对象没必要被复制(重新分配空间,data = new int 以及赋值),并且原先的类失去所有权。
data 是个类成员,在不同类里面肯定是不同的东西,占据不同的地址
wevsty
2022-06-19 23:24:19 +08:00
@woshichuanqilz

通常约定,拷贝构造是对对象做深拷贝,移动构造尽量做移动(浅拷贝)。
对于基本数据类型( int ,float 等)深拷贝和浅拷贝是一样的。
但是对于指针类型,浅拷贝通常只复制指针保存的地址。光拷贝指针中保存的地址显然不能保证不会产生资源的冲突,所以如果做深拷贝需要重新分配一块空间再对指针中指向的数据进行再次拷贝。

另外移动构造还有转移所有权的含义,移动之后原对象应该被视为已经废弃的对象(或者说没有管理任何资源的对象)。
yanqiyu
2022-06-19 23:24:39 +08:00
要是 *data 这个对象复制开销很大,或者根本就不能复制,作用就来了
sora2blue
2022-06-20 00:47:02 +08:00
可不可以这样假设:类在底层实现的时候,对内置类型的成员直接存储,对不是内置类型的成员都只存储指针;内置类型如指针的拷贝花费较少不计入,在移动构造时对这两者浅拷贝即可。相对地,在拷贝构造时对内置成员一样拷贝,对不是内置类型的成员另外拷贝一遍指针指向的成员对象,然后存储这个新的指针值在底层,而这个就是移动构造的优化对象。
所以对类的成员取地址,取到的地址都是类底层实现时内置类型成员或非内置类型成员指针的地址,比如:OP 的例子里,指针都是内置类型,直接复制即可,a.data 和 b.data 的存储位置在底层仍然是不一样的;把 data 的类型换成结构体或者类,结果是一样的,在底层指向结构体和类的指针的存储位置仍然是不一样的。
Buges
2022-06-20 02:30:23 +08:00
move 对栈上的对象来说就是 copy ,对堆上的对象来说是 copy 指针。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/860731

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX