覆盖向量的第一个元素会改变向量最后一个元素的内容。

4
在编写代码时,我注意到运行代码会返回不正确的结果,原来是我的代码中的某些部分正在更改我的协程句柄向量,我将其缩小到一行代码,在该行代码中,我用新元素覆盖了现有元素的句柄向量。
这样做还会更改向量的最后一个元素的内容(更具体地说是 myTask 标头的 bool),但不会更改中间的元素。
有人知道是什么原因导致的吗?任何帮助都感激不尽。
完整代码实现:
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <myTask.h>
#include <vector>

myTask<int> getVectorInt(std::vector<int>& array, int key, bool interleave)
{
  std::cout << "started lookup of key: " << key << std::endl;
  int result = array.at(key);
  if (interleave == true)
  {
    std::cout << "about to suspend task with key: " << key << std::endl;
    co_await std::suspend_always{};
    std::cout << "resumed task with key: " << key << std::endl;
  }
  co_return result;
}

void interleavedExecution(std::vector<int>& lookup, std::vector<int>& keys, std::vector<int>& results)
{
  // group size = number of concurrent instruction streams
  int groupsize = 3;

  // initialization of handle vector
  std::vector<std::coroutine_handle<myTask<int>::promise_type>> handles;

  // initialization of promise vector
  std::vector<myTask<int>::promise_type> promises;

  // creating/initializing first handles
  for (int i = 0; i < groupsize; ++i)
  {
    handles.push_back(getVectorInt(lookup, keys.at(i), true));
  }

  int notDone = groupsize;
  int i = groupsize;

  // interleaved execution starts here
  while (notDone > 0)
  {
    for (int handleIndex = 0; handleIndex < handles.size(); ++handleIndex)
    {
      if (!handles.at(handleIndex).promise().isDone())
      {
        handles.at(handleIndex).resume();  
        handles.at(handleIndex).promise().boolIsDone = true; 
      }
      else 
      {
        // pushing value back directly into results
        results.push_back(handles.at(handleIndex).promise().value_);
       
        if (i < keys.size())
        {
          // bug here, changes the last boolIsDone also to false (or messes with the last vector element)
          handles.at(handleIndex) = getVectorInt(lookup, keys.at(i), true);
          
          handles.at(handleIndex).promise().boolIsDone = false;
          ++i;
        }
        else { --notDone; }
      }
    }
  }
}

template <typename T> 
void outputVector(std::vector<T> toOutput)
{
  std::cout << "Results: ";
  for (int i = 0; i < toOutput.size(); ++i)
  {
    std::cout << toOutput.at(i) << ' ';
  }
}

int main()
{
  std::vector<int> lookup = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
  std::vector<int> keys = {4, 2, 0, 6, 9, 0};
  std::vector<int> results;

  // correct output: 50, 30, 10, 70, 100, 10
  // given output: 50, 30, 70, 10, 100, 10
  interleavedExecution(lookup, keys, results);
  outputVector(results);
}

包含一个布尔型的myTask头:

#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>

template <typename T>
struct myTask {
  struct promise_type {
    unsigned value_;
    ~promise_type() {
      //std::cout << "promise_type destroyed" << std::endl;
    }

    myTask<T> get_return_object() {
      return myTask<T> {
        .h_ = std::coroutine_handle<promise_type>::from_promise(*this)
      };
    }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() { return {}; }
    void unhandled_exception() { std::terminate(); }

    std::suspend_always return_value(unsigned value) {
      value_ = value;
      return {};
    }

    bool boolIsDone = false;

    auto isDone() { return boolIsDone; }
  };

  std::coroutine_handle<promise_type> h_;
  operator std::coroutine_handle<promise_type>() const { 
    //std::cout << "called handle" << std::endl;
    return h_; }

  
};

请添加 getVectorInt 函数体,并提供一个没有外部依赖的最小工作代码(minimal working code)。您能否指定所使用的编译器及其版本,因为 C++20 目前还不被许多编译器完全支持?这将有助于我们重现和定位问题。 - Jérôme Richard
1
我添加了函数和 outputVector 函数。编译器是 g++-10,使用 -fcoroutines 标志并包括头文件。除了给定的代码外,没有其他代码,因此它应该能够编译并运行。 - whoisdv
1个回答

0

结果证明,将final_suspend()的返回类型从std::suspend_never更改为std::suspend_always解决了这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接