就我的经验而言,给定代码行上的断点意味着调试器第一次在该行上中断时,该行 * 没有任何 * 内容正在执行,或者,换句话说,当调试器在断点处停止时,它会在执行该行代码 * 之前 * 停止,而不是 * 在该行代码 * 之后 * 或 * 在该行代码 * 中间 * 停止。
我不认为我曾经见过这种观点是矛盾的(尽管我的经验主要是C++,所以这就是我一直在调试的)。
然而,当涉及协程时,情况似乎并非如此。
以this code from a previous question of mine为例(它是坏的,因为代码有UB,但我所描述的问题发生在它被触发之前,所以这并不重要),其目标摘录如下:
class [[nodiscard]] CoroTaskSub {
…
public:
…
CoroTaskSub(auto h)
: hdl{h} {
}
…
};
CoroTaskSub coro() {
…
}
CoroTaskSub callCoro() {
std::cout << " callCoro(): CALL coro()\n";
co_await coro();
…
}
我做了以下工作:
1.在cout
行放置断点
1.在co_await
行放置断点
1.运行程序(此时调试器在这两个断点中的第一个断点处停止)
1.在: hdl{h} {
行,即在CoroTaskSub
类的构造函数中放置断点¹
1.继续执行程序
在这一点上,我期望调试器会在co_await
行的断点处中断,在该行的任何内容被计算之前,但是它在CoroTaskSub
的构造函数上中断了一个断点,就像coro()
已经被处理一样。
有点奇怪,不是吗?
你知道为什么会这样吗?
(¹)由于程序的结构,在main
中调用callCoro()
时,控制已经在这里传递过一次,但我只在这里放置断点,因为我想看看什么时候调用这个构造函数来构造coro()
的CoroTaskSub
。
1条答案
按热度按时间eoigrqb61#
与常规函数不同,在协程函数中,创建返回值对象是 * 第一件事 * 发生的(好吧,在创建promise和一些簿记之后)。这是在协程中的任何代码行之前,甚至在
initial_suspend
点之前。这是通过调用promise的get_return_object
函数来完成的。这是必要的,因为在
initial_suspend
点 * 挂起 * 的情况下,返回值对象需要是调用者的有效对象。