fork download
  1. /* This doc is to investigate the issue brought by reference return type of a
  2.  * functor argument std::function. We expect it can pass the bypass function
  3.  * defined in top layer to less-context bottom layer and still work as designed.
  4.  * However we see weird behavior when it is std::function<const std::string&(int)>.
  5.  * Instead, std::function<const string*(int)> works fine...
  6. */
  7. #include <iostream>
  8. #include <vector>
  9. #include <unordered_map>
  10. #include <string>
  11. #include <functional>
  12.  
  13. using namespace std;
  14.  
  15. // This class stores vectror of numbers and divisors. API getRemainderRing picks
  16. // those numbers' remainder equal to given number after division. Bypass function
  17. // is passed in as argument to print the names.
  18. class Elements {
  19. public:
  20. Elements() = default;
  21. Elements(int32_t maxNum, int32_t divisor) : _div(divisor) {
  22. _data.clear();
  23. _data.reserve(maxNum);
  24. for (int32_t i = 0; i < maxNum; i++) {
  25. _data.push_back(i);
  26. }
  27. }
  28.  
  29. void getRemainderRing(int32_t rmd, const std::function<const string&(int32_t)>& getName, string* output) {
  30. output->clear();
  31. for (int32_t i : _data) {
  32. if (i % _div == rmd) {
  33. // crashes here. getName(i) pointing to address 0
  34. *output += getName(i) + " ";
  35. }
  36. }
  37. }
  38.  
  39. private:
  40. vector<int32_t> _data;
  41. int32_t _div;
  42. };
  43.  
  44. int main () {
  45. unordered_map<int32_t, string> numToStr;
  46. numToStr[0] = "null";
  47. numToStr[1] = "eins";
  48. numToStr[2] = "zwei";
  49. numToStr[3] = "drei";
  50. numToStr[4] = "vier";
  51.  
  52. // The functor
  53. std::function<const string&(int32_t)> getName = [&numToStr](int32_t i) -> const string& { return numToStr[i]; };
  54.  
  55. Elements smallRing(4, 2); // contains {0,1,2,3}, divisor: 2
  56. string result;
  57. // This is actually to get all odd numbers < 4
  58. smallRing.getRemainderRing(1, getName, &result);
  59.  
  60. // BOOM!
  61. cout << result << endl;
  62.  
  63. return 0;
  64. }
Success #stdin #stdout 0s 4536KB
stdin
Standard input is empty
stdout
eins drei