关于c++11的一些特性(1) 右值引用&返回值优化

Tags:

先贴一段代码(在vs2015编译通过):

 1 #include <stdio.h>
 2 #include <utility>
 3 
 4 
 5 class Item {
 6 public:
 7  char name;
 8  int val;
 9 public:
10  ~Item(){
11      printf("[dtor called] (%c, %i) \n", name, val);
12  }
13  Item():name('_'), val(0) {
14      printf("[default ctor called] \n");
15  }
16  Item(char n, int v):name(n), val(v) {
17      printf("[ctor called] (%c, %i) \n", name, val);
18  }
19  Item(const Item& a) {
20      printf("[copy ctor called] (%c, %i) -> (%c, %i)\n", a.name, a.val, name, val);
21      name = a.name;
22      val = a.val;
23  }
24  Item& operator = (const Item& a)
25  {
26      printf("[operator = called] (%c, %i) -> (%c, %i)\n", a.name, a.val, name, val);
27      name = a.name;
28      val = a.val;
29      return *this;
30  }
31  Item& operator = (Item&& a)
32  {
33      printf("[move operator = called] (%c, %i) -> (%c, %i)\n", a.name, a.val, name, val);
34      name = a.name;
35      val = a.val;
36      return *this;
37  }
38 };
39 
40 Item test1(void)
41 {
42  return Item('a', 1);
43 }
44 
45 Item test2(void)
46 {
47  Item a('b',2);
48  return a;
49 }
50 
51 Item&& test3(void)
52 {
53  Item a('c', 3);
54  return std::move(a);
55 }
56 
57 Item test4(void)
58 {
59  Item a('d', 4);
60  return std::move(a);
61 }
62 
63 Item test5(void)
64 {
65  Item&& e = Item('e', 5);
66  return e;
67 }
68 
69 int main() {
70  printf("----------Item a = test1()   --------------\n");
71  Item a = test1();
72  printf("----------Item&& b = test2() --------------\n");
73  Item&& b = test2();
74  printf("----------Item&& c = test3() --------------\n");
75  Item&& c = test3();
76  printf("----------Item&& d = test4() --------------\n");
77  Item&& d = test4();
78  printf("--------- Item&& e = test5() --------------\n");
79  Item&& e = test5();
80  printf("\n----------      test end  --------------\n\n");
81  return 0;
82 }

Debug运行结果:

 1 ----------Item a = test1()   --------------
 2 [ctor called] (a, 1)
 3 ----------Item&& b = test2() --------------
 4 [ctor called] (b, 2)
 5 [copy ctor called] (b, 2) -> (? -858993460)
 6 [dtor called] (b, 2)
 7 ----------Item&& c = test3() --------------
 8 [ctor called] (c, 3)
 9 [dtor called] (c, 3)
10 ----------Item&& d = test4() --------------
11 [ctor called] (d, 4)
12 [copy ctor called] (d, 4) -> (? -858993460)
13 [dtor called] (d, 4)
14 --------- Item&& e = test5() --------------
15 [ctor called] (e, 5)
16 [copy ctor called] (e, 5) -> (? -858993460)
17 [dtor called] (e, 5)
18 
19 ----------      test end  --------------
20 
21 [dtor called] (e, 5)
22 [dtor called] (d, 4)
23 [dtor called] (b, 2)
24 [dtor called] (a, 1)

从结果可以总结出:

  • test1函数才是最正确的写法,胡乱使用&&符号反而多调用了几次函数。
  • 对比test2、test1会发现,如果要返回一个函数临时变量,最好写成匿名变量的形式(test1),这样的写法编译器才能够做返回值优化
  • 其中test3的写法是错误的,看test3的打印以及test end之后的输出可以发现,变量c并没有被成功取到函数之外,c在test3返回时就被析构了。
  • test2、test4、test5几乎是一样的(根据打印来看的话),但test2是三者中最简洁的写法。

Release运行结果:

 1 ----------Item a = test1()   --------------
 2 [ctor called] (a, 1)
 3 ----------Item&& b = test2() --------------
 4 [ctor called] (b, 2)
 5 ----------Item&& c = test3() --------------
 6 [ctor called] (c, 3)
 7 [dtor called] (c, 3)
 8 ----------Item&& d = test4() --------------
 9 [ctor called] (d, 4)
10 [copy ctor called] (d, 4) -> (<, 3805970)
11 [dtor called] (d, 4)
12 --------- Item&& e = test5() --------------
13 [ctor called] (e, 5)
14 [copy ctor called] (e, 5) -> (? 1)
15 [dtor called] (e, 5)
16 
17 ----------      test end  --------------
18 
19 [dtor called] (e, 5)
20 [dtor called] (d, 4)
21 [dtor called] (b, 2)
22 [dtor called] (a, 1)

对比Debug版的输出,会发现test2函数被编译优化成test1了。

当然,还是尽量把代码写成test1的写法吧。简洁得多。

(未经授权禁止转载)
Written on October 30, 2015

博主将十分感谢对本文章的任意金额的打赏^_^