C++ 11 新特性(七)

今天任性,想写一个自己感兴趣的问题,move 语义。

先上代码

#include <iostream>

class A {
   public:
      A() {
         std::cout << "constructor A" << std::endl;
      }
      ~A() {
         std::cout << "destructor A" << std::endl;
      }
};

A func () {
   A a;

   return std::move(a);
}

int main() {
   auto a = func();

   std::cout << "flag 1" << std::endl;

   return 0;
}

问题是打印什么?

如果没有 move 语义,我想你一定知道打印什么,现在的问题是有了 move 之后,现在你还能知道吗?

上结果,然后说下原因

constructor A
destructor A
flag 1
destructor A

move 抵消了一次 constructor, 但是却出现了两次 destructor,这个和传统 C++ 是相悖的。那么现在有问题了,由于调用了两次 destructor 如何解决资源重复释放的问题?比如我在构造函数里面 new 了一个对象,需要在析构函数里面释放,这个问题怎么解决?

C++ 使用了一个 move constructor, 这个东西有点类似 copy constructor,代码如下:

#include <iostream>

class A {
   public:
      A() {
         std::cout << "constructor A" << std::endl;
      }
      ~A() {
         std::cout << "destructor A" << std::endl;
      }

      A( A & oth) {
         std::cout << "copy constructor A" << std::endl;
      }

      A(A && oth) {
         std::cout << "move constructor A" << std::endl;
      }
};

A func () {
   A a;

   return std::move(a);
}

int main() {
   A a = func();

   std::cout << "flag 1" << std::endl;

   return 0;
}

输出结果如下:

constructor A
move constructor A
destructor A
flag 1
destructor A

好了,资源释放的问题,我们就放到 move constructor 里面,为了对比,我写个 copy constructor 的过程,去除了所有可能的异常case,只是做个示范,代码如下:

#include <iostream>

class A {
   public:
      A() {
         std::cout << "constructor A" << std::endl;

         num = new int(100);
      }
      ~A() {
         if (num == nullptr) {
            std::cout << ">>>>num is nullptr" << std::endl;
         } else {
            std::cout << ">>>>num value is " << *num << std::endl;
            delete num;
         }
         std::cout << "destructor A" << std::endl;
      }

      A( A & oth) {
         std::cout << "copy constructor A" << std::endl;

         num = new int;

         num = oth.num;
      }

      A(A && oth) {
         std::cout << "move constructor A" << std::endl;

         num = std::move(oth.num);
         oth.num = nullptr;
      }

   public:
      int * num;
};

A func () {
   A a;

   return std::move(a);
}

int main() {
   A a = func();

   std::cout << "flag 1" << std::endl;

   return 0;
}

看到区别了吗,move constructor 是不需要 new 新对象的,只要将对应的字段也move一下,原有的字段设置成一个无效的值就行了,这样就保证了资源的安全,代码运行结果如下:

constructor A
move constructor A
>>>>num is nullptr
destructor A
flag 1
>>>>num value is 100
destructor A

这里面有很多的问题,我没有说完,比如如果不写move constructor, 程序会crash 吗?

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

相关阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 179,355评论 25 708
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 14,129评论 2 59
  • 【0929今日剽悍】 今天收到了猫叔送的礼物啦——一盒巧克力月饼,很特别,至少我没有吃过这种口味的。没有想到猫叔即...
    好听的暖阳阅读 350评论 0 0
  • 目录 上一章 开卷有言 水神共工与火神祝融战,共工败而怒触不周山。不周山乃天之支柱,支柱...
    酉木阅读 376评论 7 4
  • A,B,C,D,E哈哈,如果说起维生素可以唱一个歌了。其实,维生素是按其被发现的顺序命名的。 今天,我...
    8ad130a09427阅读 324评论 6 4

友情链接更多精彩内容