C++ std::move 和 unique_ptr 2020-11-01

新手写出来的c++程序,估计到处都是可以优化的坑!

第一点

    std::string str = "Hello";
    std::vector<std::string> v;

    cout<< "str.length is :" << str.length()<<endl;
    cout<< "str.capacity is :"<< str.capacity()<<endl;

    v.push_back(str); //使用push_back(const T&) 重载,调用时,会发生copy
    std::cout << "After push_back 1, str is \"" << str << std::endl;


    v.push_back(std::move(str));//会使用 push_back(T&&) 重载,不会发生copy,但是str 里面东西没了
    std::cout << "After push_back 2, str is \"" << str << std::endl;

    std::cout << "The contents of the vector are \"" << v[0]
              << ", " << v[1] << std::endl;

    cout<< "str.length is :" << str.length()<<endl;
    cout<< "str.capacity is :"<< str.capacity()<<endl;

输出如下:

str.length is :5
str.capacity is :15
After push_back 1, str is "Hello
After push_back 2, str is "
The contents of the vector are "Hello, Hello
str.length is :0
str.capacity is :15

第二点

定义了以下类和方法

class AAA{
private:
    int aaa=5;
public:
    ~AAA()=default;
    void show(){
        cout << "AAA.aaa = "<< aaa<<endl;
    }
};
void Test(std::unique_ptr<AAA> pp){
    pp->show();
}

然后就很自然的写了以下调用

int main(int argc, char *argv[])
{
    std::unique_ptr<AAA> pp = std::make_unique<AAA>();
    Test(pp);//    <--------注意这里
}

一编译就报错.

In function ‘int main(int, char**)’:
main.cpp:127:12: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = AAA; _Dp = std::default_delete<AAA>]’
  127 |     Test(pp);
      |            ^

很奇怪,
我调用一个参数为:std::unique_ptr<AAA>的函数,
按照要求,我传入了一个 std::unique_ptr<AAA> 类型的变量 pp,却无法编译通过.

改成这样就编译通过了:

int main(int argc, char *argv[])
{
    std::unique_ptr<AAA> pp = std::make_unique<AAA>();
    Test(std::move(pp)); // <-------------添加了std::move调用

   
}

输出为:

AAA.aaa = 5

然后继续,修改代码,看看move后发生了什么,
代码改为:

int main(int argc, char *argv[])
{
    std::unique_ptr<AAA> pp = std::make_unique<AAA>();
    Test(std::move(pp));

    if(pp ==nullptr){
        cout << "after call Test,pp is nullptr"<<endl;
    }else
    {
        cout << "after call Test,pp is not nullptr"<<endl;
    }
}

输出如下:

AAA.aaa = 5
after call Test,pp is nullptr

这就对了,move以后没了.
但还是有点区别:

  • String 在move以后,本身没有变成null,但内容没有了.
  • unique_ptr<>,在move以后,本身变成了null.

第三点

实际上是接着第二点的

我发现 std::unique_ptr<AAA> pp ,实际上是类unique_ptr<T>的一个实例,既然是类的实例,作为函数参数时,就应该使用引用方式. 以及右值引用方式,于是就改成了下面的代码(请手动忽略没加const的问题)

void Test(std::unique_ptr<AAA>& pp){
    cout << "in Test(std::unique_ptr<AAA>& pp)" << endl;
    pp->show();
}
void Test(std::unique_ptr<AAA>&& pp){
     cout << "in Test(std::unique_ptr<AAA>&& pp)" << endl;
    pp->show();
}
int main(int argc, char *argv[])
{
    std::unique_ptr<AAA> pp = std::make_unique<AAA>();
    Test(pp); //<--------------注意这里

    if(pp ==nullptr){
        cout << "after call Test,pp is nullptr"<<endl;
    }else
    {
        cout << "after call Test,pp is not nullptr"<<endl;
    }
}

输出为:

in Test(std::unique_ptr<AAA>& pp)
AAA.aaa = 5
after call Test,pp is not nullptr

看来调用的第一个引用参数的方法,由于没有使用std::move,调用后pp 不是nullptr.

然后再试:

   std::unique_ptr<AAA> pp = std::make_unique<AAA>();

    Test(std::move(pp));//<--------------注意这里

     if(pp ==nullptr){
        cout << "after  call Test,pp is nullptr"<<endl;
    }else
    {
        cout << "after  call Test,pp is not nullptr"<<endl;
        pp->show();
    }

    if(pp.get() == nullptr){
        cout << "after  call Test,pp.get()  is nullptr"<<endl;
    }else
    {
        cout << "after  call Test,pp.get()  is not nullptr"<<endl;
        pp.get()->show();
    }



这次使用了std::move,调用了右值引用参数的方法,但是结果有点意外:

in Test(std::unique_ptr<AAA>&& pp)
AAA.aaa = 5
after  call Test,pp is not nullptr
AAA.aaa = 5
after  call Test,pp.get()  is not nullptr
AAA.aaa = 5

WTF,为啥 调用std::move之后竟然不变成nullptr.

不知对std::move的理解有问题还是实现有问题!!! 哭阿!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容