【问题标题】:What's the problem of saving pointer of vector inside std::map在 std::map 中保存向量指针的问题是什么
【发布时间】:2021-05-13 03:46:26
【问题描述】:

我正在尝试通过记忆找到最佳总和,但是当将矢量指针保存在地图中时,值不断附加在矢量内并得到错误的矢量。 如果我注释掉地图插入,它可以正常工作。 如果尝试通过引用将矢量保存在地图中,则无法保存 nullptr。

std::vector<int> *bestSumV(int target, int nums[], int size) {

  static std::map<int, std::vector<int> *> memo;

  if (memo.find(target) != memo.end())
    return memo.at(target);

  if (target == 0)
    return new std::vector<int>();

  if (target < 0)
    return NULL;

  std::vector<int> *bestCom = nullptr;

  for (int i = 0; i < size; i++) {

    int reminder = target - nums[i];

    std::vector<int> *reminderResult = bestSumV(reminder, nums, size);

    if (reminderResult != NULL) {

      reminderResult->push_back(nums[i]);

      if (bestCom == nullptr || reminderResult->size() < bestCom->size()) {
        bestCom = static_cast<std::vector<int> *>(reminderResult);
      }
    }
  }
  // if i commented out the map insertion i am getting the correct value
  // and getting a vector of 5 items

  memo.insert(std::make_pair(target, std::move(bestCom)));

  return bestCom;
}

void runHowbestTest() {

  int testArray[] = {5, 4, 2};

  std::vector<int> *bestSum25 = bestSumV(25, testArray, 3);

  for (int i = 0; i < bestSum25->size(); i++) {
    std::cout << "the items  " << bestSum25->at(i) << std::endl;
  }
}

【问题讨论】:

  • 我打赌指针太多是问题所在。请在问题中包含您的代码的minimal reproducible example
  • 为什么你需要来存储一个nullptr?如果你想要一个“空”元素,你不能在地图的那个位置存储一个空向量吗?
  • @youssefmyh 除了最大的建议,在这种情况下不存储元素怎么样?如果这些都不是一个选项,则使用std::optional&lt;std::vector&gt; 并存储nullopt
  • @youssefmyh 返回一个空向量会破坏目标检查 -- 换句话说,你写了代码,现在你把自己画到了一个角落。记忆只是一种技术——你决定使用nullptr——其他人会决定使用空向量,并编写代码来处理它。
  • 指针与否,你不应该动态分配标准容器。这几乎总是一个错误。至少比原始的new(和delete)更喜欢智能指针

标签: c++ c++11 memoization


【解决方案1】:

bestComstd::vector&lt;int&gt; * 不要std::move 它。这毫无意义,并且使代码难以阅读。

reminderResult 已经是std::vector&lt;int&gt; *,不需要static_cast&lt;std::vector&lt;int&gt; *&gt;

在这条线上

memo.insert(std::make_pair(target, std::move(bestCom)));

bestCom 可能为空。发生这种情况时,

if (memo.find(target) != memo.end())
    return memo.at(target);

将返回并绕过函数逻辑。你需要:

if (memo.find(target) != memo.end() && memo.at(target))
    return memo.at(target);

而且,最有可能的是真正的问题:

// returns a memoized value
std::vector<int> *reminderResult = bestSumV(reminder, nums, size); 
...
  // modifies it.
  reminderResult->push_back(nums[i]);

您不能修改记忆值并期望它有效。

使用对象而不是指针解决了这个问题:https://godbolt.org/z/v35oT4。但我没有声明它对性能的影响。

【讨论】:

  • 不是说这是错误的(我真的不知道),但“返回并绕过功能逻辑”正是memo的用途。如果它包含一个nullptr for key target,那么只是因为它是在之前调用传递函数逻辑后插入的
  • @largest_prime_is_463035818 备忘录用于将时间复杂度从 O(n^m) 降低到 O(n*m) 非常感谢您的评论,我看到 std::move 和 static_cast 没用
猜你喜欢
  • 1970-01-01
  • 2016-05-18
  • 2020-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-22
  • 2020-05-31
相关资源
最近更新 更多