Компиляция приведенного ниже примера кода с помощью 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