Повышение контекста l oop Условие побочных эффектов - PullRequest
0 голосов
/ 28 марта 2020

Компиляция приведенного ниже примера кода с помощью clang10 -std=c++17 -Wall выдает предупреждение:

предупреждение: переменная 'done' используется в условии l oop, не изменяется в теле l oop [- Wfor-l oop -анализ]

В нормальной функции это было бы правильно, однако здесь использование boost::context означает, что поток управления завершается, а затем снова входит в функцию f, а модификация условной переменной l oop done вместо этого происходит в main.

В моей реальной программе передаваемый указатель функции вместо f может быть из другой единицы перевода .

Является ли эта программа действительной, будет ли она работать так, как можно было бы наивно ожидать ее прочтения, и не имела бы UD?

Я не очень разбираюсь в этой области, поэтому размышляю: например, может ли функция как f скажем, с именем g, определенным в другом TU, компилятор "видит", что g не меняет переменную done (как говорит clang), а затем превращает это в бесконечное l oop или что-то похожее соток? Или компилятор не сможет доказать это точно из-за какого-то побочного эффекта, подобного этому, влияющего на значение done, и все это работает так, как я ожидаю?

    #include <boost/context/fiber.hpp>

    #include <iostream>
    #include <string>
    #include <utility>

    namespace ctx = boost::context;

    void f(ctx::fiber&& sink, const int& in, bool& out, const bool& done) {
      std::cout << "f: Entry" << "\n";
      for (; !done; sink = std::move(sink).resume()) {
        out = in % 2 == 0;
        std::cout << "f: " << in << " -> " << out << "\n";
      }
      std::cout << "f: Exit" << "\n";
    }

    int main() {
      std::cout << std::boolalpha;

      int in = 0;
      bool out = false;
      bool done = false;

      using Solver = void (*const)(ctx::fiber&&, const int&, bool&, const bool&);
      Solver p = &f;

      ctx::fiber source{[&in, &out, &done, p] (ctx::fiber&& sink) {
        std::cout << "Fibre: Entry" << "\n";
        p(std::move(sink), in, out, done);
        std::cout << "Fiber: Exit" << "\n";
        return std::move(sink);
      }};

      std::cout << "main: Starting looping" << "\n";
      for (int j = 0; j < 3 ; ++j) {
        in = j;
        source = std::move(source).resume();
        std::cout << "main: for input " << in << " got output " << out << " from f" << "\n";
      }

      done = true;
      std::move(source).resume();
      std::cout << "main: Exit" << "\n";
    }

Вывод:

main: Starting looping
Fibre: Entry
f: Entry
f: 0 -> true
main: for input 0 got output true from f
f: 1 -> false
main: for input 1 got output false from f
f: 2 -> true
main: for input 2 got output true from f
f: Exit
Fiber: Exit
main: Exit
...