聊聊C++临时对象的析构时间点------顺便再次提醒大家谨慎使用string的c_str方法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/stpeace/article/details/46461167
            </div>
                                                <!--一个博主专栏付费入口-->
         
         <!--一个博主专栏付费入口结束-->
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
                                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
            <div class="htmledit_views" id="content_views">

       C++临时对象的析构?这不是很简单么?其实没那么简单。 我们先看看如下程序吧:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. string test()
  5. {
  6. return "abc";
  7. }
  8. int main()
  9. {
  10. const char *p = test().c_str();
  11. cout << p << endl;
  12. return 0;
  13. }
        你可能迫切地期待结果为:abc, 其实不然。 为了简便起见, 我们简化一下上述程序:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. int main()
  5. {
  6. const char *p = string( "abc").c_str();
  7. cout << p << endl;
  8. return 0;
  9. }
       注意, 结果不是abc. 为什么呢? 我先直接说吧:string("abc")是一个临时对象, 在执行完 const char *p = string("abc").c_str();这个语句后, 临时对象就析构了, 也就是说p指向的区域中的值变了。 所以, 结果自然不是abc.


       这就引出了如下问题: 临时对象是何时析构的呢? 我们先看一个程序:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class A
  5. {
  6. public:
  7. A()
  8. {
  9. cout << "A constructor" << endl;
  10. }
  11. ~A()
  12. {
  13. cout << "A destructor" << endl;
  14. }
  15. };
  16. int main()
  17. {
  18. A(); // 临时对象
  19. printf( "end xxx\n");
  20. printf( "end yyy\n");
  21. return 0;
  22. }
      稍微懂一点C++的人会说, 结果是:

A constructor
end xxx
end yyy
A destructor

      其实, 上述结果是错误的, 真正的结果是:

A constructor
A destructor
end xxx
end yyy

     

       看来, 在执行完第一个语句后, 临时对象A()就析构了, 我们来看看汇编, 验证一下吧:


        我们看到, 临时对象确实是在printf之前析构的。


        好, 我们接着看:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class A
  5. {
  6. public:
  7. A()
  8. {
  9. cout << "A constructor" << endl;
  10. }
  11. ~A()
  12. {
  13. cout << "A destructor" << endl;
  14. }
  15. };
  16. int main()
  17. {
  18. A(), // 注意, 是逗号运算符
  19. printf( "end xxx\n");
  20. printf( "end yyy\n");
  21. return 0;
  22. }
      运行结果为:

A constructor
end xxx
A destructor
end yyy


      不要惊讶, 查看汇编代码就知道, 临时对象是在 printf("end xxx\n");后析构的。


      继续看代码:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class A
  5. {
  6. public:
  7. A()
  8. {
  9. cout << "A constructor" << endl;
  10. }
  11. ~A()
  12. {
  13. cout << "A destructor" << endl;
  14. }
  15. };
  16. int main()
  17. {
  18. A(), // 注意, 是逗号运算符
  19. printf( "end xxx\n"), // 注意, 是逗号运算符
  20. printf( "end yyy\n");
  21. return 0;
  22. }
      运行结果为:

A constructor
end xxx
end yyy
A destructor

       不要惊讶, 查看汇编代码就知道, 临时对象是在 printf("end xxx\n");后析构的。


       由此可见, 临时对象是在遇到其后的第一个分号(语句结束处)析构的。


        好, 我们再看看:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. int main()
  5. {
  6. const char *p = string( "abc").c_str(); // 临时对象在执行完该句后析构了
  7. cout << p << endl; // 此时p指向垃圾值
  8. return 0;
  9. }
       一切一目了然。


       大家在使用临时对象的时候要留个心眼, 尤其是使用string的c_str时, 一旦出错, 经常排查半天, 最后才发现栽倒在此处。 鉴于容易出错, 最后, 我们再看一眼吧:


  
  
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. int main()
  5. {
  6. const char *p = ( string( "abc") + string( "def")).c_str(); // 临时对象在执行完该句后析构了
  7. cout << p << endl; // 此时p指向垃圾值
  8. return 0;
  9. }

      OK,  本文先到此为止。


       备注: 在上面的程序中, 我使用的编译器是VC++6.0, 后来网友“时光”提醒我, g++的编译器会有不同的表现。 在此, 感谢“时光”得意。 另外, 为了写出高质量的可移植代码, 仍需要注意避免使用临时string对象的c_str方法。



发布了209 篇原创文章 · 获赞 80 · 访问量 11万+
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/stpeace/article/details/46461167
            </div>
                                                <!--一个博主专栏付费入口-->
         
         <!--一个博主专栏付费入口结束-->
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
                                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
            <div class="htmledit_views" id="content_views">

猜你喜欢

转载自blog.csdn.net/wc996789331/article/details/103166416