线程退出后回调访问栈上vector是否属于C++未定义行为?
线程退出后访问其栈上vector是否属于未定义行为?
问题背景
代码中注册了一个用于清理操作的stop_callback:
- 调用
request_stop请求停止时,回调从main线程触发,工作线程随即退出 - 回调等待1秒后,访问工作线程栈上的
std::vector,此时工作线程已执行完最后一行代码,线程不存在,vector理论上已失效 - 实际测试中,valgrind和
g++ -fsanitize=address未检测到任何问题,size()输出始终符合预期
核心疑问:只要main中的request_stop未返回,访问线程栈上的vector是否合法?这段代码是否属于未定义行为?
测试代码
#include <iostream> #include <thread> #include <vector> #include <stop_token> #include <chrono> using namespace std::chrono_literals; void thread_func(std::stop_token st) { std::vector<int> v; std::stop_callback cb{st, [&v] { std::this_thread::sleep_for(1000ms); for (int i=0; i<1234; ++i) v.push_back(i); std::cout << "call back from: " << std::this_thread::get_id() << ", size " << v.size() << '\n'; }}; while (!st.stop_requested()) { // ... } std::cout << "thread finished " << std::this_thread::get_id() << '\n'; } int main() { std::stop_source src; auto t = src.get_token(); auto thr = std::jthread{thread_func, t}; std::this_thread::sleep_for(500ms); bool b = src.request_stop(); std::cout << "main finished " << std::this_thread::get_id() << '\n'; }
结论与分析
这段代码属于明确的未定义行为,原因如下:
- 对象生命周期结束:工作线程栈上的
std::vector<int> v是局部对象,其生命周期从构造完成开始,到thread_func函数执行完毕(工作线程打印"thread finished...")时结束——此时栈帧被销毁,v占用的内存空间被标记为可用。 - 回调访问已销毁对象:
stop_callback的回调函数在main线程执行,回调中的sleep_for(1000ms)会让main线程等待1秒,此时工作线程早已完成thread_func的执行,v的生命周期已经结束。此时访问该对象的成员函数(push_back、size),完全符合C++标准中未定义行为的范畴。
C++标准引用
根据C++20标准相关条款:
- [basic.life]/1:对象的生命周期始于其构造完成,终于其析构完成。对于自动存储期对象(栈对象),当包含它的块执行完毕时,对象被析构,生命周期结束。
- [basic.life]/6:若对象生命周期已结束,即使其内存空间尚未被重新使用,访问该对象的非静态数据成员或调用其成员函数,均属于未定义行为;若内存空间已被重新使用,行为同样未定义。
工具未检测到问题的原因
valgrind和AddressSanitizer未报错,只是因为栈内存暂时未被覆盖或重新分配,属于偶然情况。未定义行为的表现是不可预测的,可能在不同编译器、不同运行环境、不同调用场景下出现崩溃、数据篡改、程序异常退出等问题。
内容的提问来源于stack exchange,提问作者curiousguy12
相关产品推荐
相关产品推荐

