fork(1) download
  1. #include <iostream>
  2. #include <vector>
  3. #include <initializer_list>
  4.  
  5. struct Test {
  6. std::string pString;
  7. Test(){
  8. std::cout << "construct" << std::endl;
  9. }
  10. Test(const std::string& aString):pString(aString){
  11. std::cout << "construct(prepare)" << std::endl;
  12. }
  13. Test(std::nullptr_t){
  14. std::cout << "construct(nullptr)" << std::endl;
  15. }
  16. Test& operator = (std::nullptr_t){
  17. std::cout << "assign(nullptr)" << std::endl;
  18. return *this;
  19. }
  20. Test(const Test& aTest){
  21. std::cout << "construct(const self&)" << std::endl;
  22. pString = aTest.pString;
  23. }
  24. Test& operator = (const Test& aTest){
  25. std::cout << "assign(const self&)" << std::endl;
  26. if(&aTest != this){
  27. pString = aTest.pString;
  28. }
  29. return *this;
  30. }
  31. Test(Test&& aTest){
  32. std::cout << "construct(self&&)" << std::endl;
  33. std::swap(pString, aTest.pString);
  34. }
  35. Test& operator = (Test&& aTest){
  36. std::cout << "assign(self&&)" << std::endl;
  37. if(&aTest != this){
  38. std::swap(pString, aTest.pString);
  39. }
  40. return *this;
  41. }
  42. ~Test(){
  43. std::cout << "destroy" << std::endl;
  44. }
  45. };
  46.  
  47. template <typename Output_t, typename ...Input_t>
  48. inline Output_t& Compact(Output_t& aOutput, Input_t&& ...aInput){
  49. // should I do this?
  50. if(!sizeof...(aInput)){
  51. return aOutput;
  52. }
  53.  
  54. // I like typedefs as they shorten the code :)
  55. typedef typename Output_t::value_type Type_t;
  56.  
  57. // can be either lvalues or rvalues in the initializer_list when it's populated.
  58. std::initializer_list<Type_t> vInput = { std::forward<Input_t>(aInput)... };
  59.  
  60. // now move the initializer_list into the vector.
  61. aOutput.reserve(aOutput.size() + vInput.size());
  62. for(auto vIter(vInput.begin()), vEnd(vInput.end()); vIter != vEnd; ++vIter){
  63. // move (don't copy) out the lvalue or rvalue out of the initializer_list.
  64. aOutput.emplace_back(std::move(const_cast<Type_t&>(*vIter))); // <- THIS!
  65. }
  66.  
  67. // done! :)
  68. return aOutput;
  69. }
  70.  
  71.  
  72. int main() {
  73. // assign the values to track both string and memory moves
  74. Test vTestL("lvalue"), vTestR("rvalue");
  75. // claim 1KB of memory so results are not affected by SSO (small string optimization)
  76. vTestL.pString.reserve(1024);
  77. vTestR.pString.reserve(1024);
  78.  
  79. std::cout << std::endl;
  80. std::cout << "Input(before):" << std::endl;
  81. std::cout << "LValue: " << vTestL.pString
  82. << " - 0x" << reinterpret_cast<const void*>(vTestL.pString.c_str())
  83. << " -- (should be unscathed)" << std::endl;
  84. std::cout << "RValue: " << vTestR.pString
  85. << " - 0x" << reinterpret_cast<const void*>(vTestR.pString.c_str())
  86. << " -- (should be relocated)" << std::endl;
  87. std::cout << std::endl;
  88.  
  89. std::vector<Test> vTests;
  90. Compact(vTests, vTestL, std::move(vTestR));
  91.  
  92. std::cout << std::endl;
  93. std::cout << "Input(after):" << std::endl;
  94. std::cout << "LValue: " << vTestL.pString
  95. << " - 0x" << reinterpret_cast<const void*>(vTestL.pString.c_str())
  96. << " -- (should be unscathed)" << std::endl;
  97. std::cout << "RValue: " << vTestR.pString
  98. << " - 0x" << reinterpret_cast<const void*>(vTestR.pString.c_str())
  99. << " -- (should be relocated)" << std::endl;
  100. std::cout << std::endl;
  101.  
  102. std::cout << std::endl;
  103. std::cout << "Output:" << std::endl;
  104. std::cout << "LValue: " << vTests[0].pString
  105. << " - 0x" << reinterpret_cast<const void*>(vTests[0].pString.c_str())
  106. << " -- (should be unscathed)" << std::endl;
  107. std::cout << "RValue: " << vTests[1].pString
  108. << " - 0x" << reinterpret_cast<const void*>(vTests[1].pString.c_str())
  109. << " -- (should be unscathed)" << std::endl;
  110. std::cout << std::endl;
  111.  
  112. return 0;
  113. }
Success #stdin #stdout 0s 3436KB
stdin
Standard input is empty
stdout
construct(prepare)
construct(prepare)

Input(before):
LValue: lvalue - 0x0x9957044 -- (should be unscathed)
RValue: rvalue - 0x0x995745c -- (should be relocated)

construct(const self&)
construct(self&&)
construct(self&&)
construct(self&&)
destroy
destroy

Input(after):
LValue: lvalue - 0x0x9957044 -- (should be unscathed)
RValue:  - 0x0x804b62c -- (should be relocated)


Output:
LValue: lvalue - 0x0x9957044
RValue: rvalue - 0x0x995745c

destroy
destroy
destroy
destroy