到底何时使用std::move


再最近的工程中,发现有滥用std::move的现象,现在对std::move在不同场景下的作用做一个简单分析与总结。
在c++编程中,为了提高程序运行的效率,可使用std::move来将一个左值转变成右值,或者说让被std::move包裹的变量具有可移动属性,能够将自身的持有的资源转移到另一个对象中。
那么何时该使用std::move呢,接下来我将通过一系列的试验程序来探索std::move在不同情况下的表现。

由基本类型构成的结构体

我们先定义一个由基本类型构成的结构体

struct TestStruct1{
    int a;
    char b;
};

然后测试TestStruct1在std::move中的具体表现:

	TestStruct1 t1;
    t1.a = 10;
    t1.b = 'a';

    printf("t1 value: a = %d b = %c  t1 address:a = %0x b = %0x \n",
            t1.a,t1.b,&t1.a,&t1.b);

    TestStruct1 t2(std::move(t1));
    printf("t1 value: a = %d b = %c  t1 address:a = %0x b = %0x \n",
            t1.a,t1.b,&t1.a,&t1.b);
    printf("t2 value: a = %d b = %c  t2 address:a = %0x b = %0x \n",
            t2.a,t2.b,&t2.a,&t2.b);

获得输出:

t1 value: a = 10 b = a  t1 address:a = 4feb39f8 b = 4feb39fc 
t1 value: a = 10 b = a  t1 address:a = 4feb39f8 b = 4feb39fc 
t2 value: a = 10 b = a  t2 address:a = 4feb3a00 b = 4feb3a04 

可以看到对基本的类型构造时使用std::move,其效果跟普通的赋值没有任何区别。

拥有指针的结构体

接下来我们让结构体中包含基本类型的指针

    struct TestStruct2{
        int* a;
        char* b;
    };

我们对这个结构体使用std::move,并查看输出

    TestStruct2 t1{new int[1],"Hello"};
    *(t1.a) = 2;
    printf("t1 value: a = %d b = %s t1 address:a = %0x b = %0x \n",
            *(t1.a),t1.b,t1.a,t1.b);
    TestStruct2 t2(std::move(t1));
    printf("t1 value: a = %d b = %s  t1 address:a = %0x b = %0x \n",
            *(t1.a),t1.b,t1.a,t1.b);
    printf("t2 value: a = %d b = %s  t2 address:a = %0x b = %0x \n",
            *(t2.a),t2.b,t2.a,t2.b);
t1 value: a = 2 b = Hello  t1 address:a = 6c948e70 b = 6bed1b6e 
t1 value: a = 2 b = Hello  t1 address:a = 6c948e70 b = 6bed1b6e 
t2 value: a = 2 b = Hello  t2 address:a = 6c948e70 b = 6bed1b6e

可以看出使用std::move的效果跟普通的赋值效果没有任何区别;

对string使用std::move

当对string使用std::move来调用其移动构造函数时,根据字符串长度的不同,会右不同的输出结果:
字符串较短时

    std::string t1 = "Hello";
    printf("t1 value:%s t1 address %0x \n",t1.c_str(),t1.c_str());
    std::string t2(t1);
    printf("t2 value:%s t2 address %0x \n",t2.c_str(),t2.c_str());
    std::string t3(std::move(t1));
    printf("t1 value:%s t1 address %0x \n",t1.c_str(),t1.c_str());
    printf("t3 value:%s t3 address %0x \n",t3.c_str(),t3.c_str());
t1 value:Hello t1 address ec190820 
t2 value:Hello t2 address ec190840 
t1 value: t1 address ec190820 
t3 value:Hello t3 address ec190860

字符串较长时

t1 value:Helloooooooooooooooooooooo t1 address 1e070e70 
t2 value:Helloooooooooooooooooooooo t2 address 1e0712b0 
t1 value: t1 address 87ef6a90 
t3 value:Helloooooooooooooooooooooo t3 address 1e070e70 

可以看到当字符串较短时,t3中字符串的地址跟t1中不相同,而字符串较长时t3中字符串的地址跟t1中的相同,意味着当字符串较长是,通过string的移动构造函数会直接将t1中的字符串地址给t3。

总结

从上述试验中可以看出,std::move的作用是将一个左值变成一个右值,以供移动构造函数使用。
如果一个变量并没有定义移动构造函数,那么其将调用默认的移动构造函数,其功能与普通的构造函数相同(如果变量内部的成员变量也没定义移动构造函数的话);
因此std::move应该用在自定义了移动构造函数的那些变量中。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C++11标准中,引入了线程库来支持多线程编程。std::thread是线程库中的一个类,用于创建和管理线程。std::move是C++中的一个右值引用函数,用于将对象从一个变量转移到另一个变量,同时可以避免对象的拷贝和移动的开销。在多线程编程中,std::thread和std::move是两个非常有用的工具。 std::thread可以在一个独立的执行线程中执行给定的函数。使用std::thread的最常见方式是传递一个函数指针或可调用对象的引用给它的构造函数。当std::thread对象被创建时,它会启动一个线程并运行指定的函数。该构造函数的参数列表可以包括任何给定函数的参数。线程的返回值可以通过std::future<T>对象获得,其中,T是被线程函数返回值的类型。 在多线程编程中,std::move可以用于将线程对象转移到一个新的线程管理器对象中。例如,在程序中,有时需要将一个线程对象转移到一个新的std::thread管理器对象中,以便在不同线程中执行相同的任务。这时可以使用std::move来移动线程对象,避免了拷贝和移动的开销。 同时需要注意的是,当使用std::move将线程对象转移到另一个管理器对象时,应该确保在源线程对象中不再使用该对象,否则可能会导致未定义的行为。因此,当使用std::move在多线程环境中移动对象时,必须小心谨慎。需要仔细考虑线程对象的生命周期,以确保线程的正确执行。 总之,std::thread和std::move是在C++11中引入的非常有用的工具,在多线程编程中可以大大提高程序的性能和效率。同时需要注意在使用时小心谨慎,确保使用正确和安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值