fork download
  1. //#define BUG_CASE
  2.  
  3. #include <iostream>
  4. #include <deque>
  5. #include <algorithm>
  6. #include <utility>
  7. #include <memory>
  8. using namespace std;
  9.  
  10. deque<bool> pool;
  11.  
  12. class ExpressionTemp;
  13. class Scalar
  14. {
  15. bool *alive;
  16.  
  17. friend class ExpressionTemp;
  18.  
  19. Scalar(const Scalar&);
  20. Scalar &operator=(const Scalar&);
  21. Scalar &operator=(Scalar&&);
  22. public:
  23. Scalar()
  24. {
  25. pool.push_back(true);
  26. alive=&pool.back();
  27. }
  28. Scalar(Scalar &&rhs)
  29. : alive(0)
  30. {
  31. swap(alive,rhs.alive);
  32. }
  33. ~Scalar()
  34. {
  35. if(alive)
  36. (*alive)=false;
  37. }
  38. };
  39. class ExpressionTemp
  40. {
  41. #ifndef BUG_CASE
  42. unique_ptr<Scalar> resource; // can be in separate type
  43. #endif
  44. bool *operand_alive;
  45. public:
  46. ExpressionTemp(const Scalar &s)
  47. : operand_alive(s.alive)
  48. {
  49. }
  50. #ifndef BUG_CASE
  51. ExpressionTemp(Scalar &&s)
  52. : resource(new Scalar(move(s))), operand_alive(resource->alive)
  53. {
  54. }
  55. #endif
  56. void do_job()
  57. {
  58. if(*operand_alive)
  59. cout << "captured operand is alive" << endl;
  60. else
  61. cout << "captured operand is DEAD!" << endl;
  62. }
  63. };
  64.  
  65. template<typename T>
  66. ExpressionTemp expression(T &&s)
  67. {
  68. return {forward<T>(s)};
  69. }
  70. int main()
  71. {
  72. {
  73. expression(Scalar()).do_job(); // OK, Scalar is moved to temporary
  74. }
  75. {
  76. Scalar lv;
  77. auto &&rvref=expression(lv);
  78. rvref.do_job(); // OK, lv is still alive
  79. }
  80. {
  81. auto &&rvref=expression(Scalar());
  82. rvref.do_job(); // OK, Scalar is moved into rvref
  83. }
  84. return 0;
  85. }
  86.  
Success #stdin #stdout 0s 3020KB
stdin
Standard input is empty
stdout
captured operand is alive
captured operand is alive
captured operand is alive