首页 > 解决方案 > set_new_handler 是否将 new_handler 存储在线程本地存储中?

问题描述

有人询问set_new_handler在多线程环境中是否安全。我想知道 C++ 11 及更高版本的 C++ 标准库实现是否使用该thread_local功能来存储std::new_handler. 如果实现不使用thread_local,为什么不呢?这似乎使该功能在多线程程序中更加强大。

我也没有真正看到set_new_handler重载new和设置 astd::new_handler并创建(并拥有对)一个对象的类的工作方式,该对象也重载new并设置自己的std::new_handler. 如果拥有类具有获取/释放内存的选项,而拥有的对象决定调用中止/终止,我希望这将特别令人震惊。

我希望通常的建议是使用nothrowversion of newand forget set_new_handler。如果这是一个普遍的观点,为什么set_new_handler标准库中没有弃用的功能?

标签: c++c++11memory

解决方案


new_handler不是,也从未期望是线程本地构造。它始终是全球性的,这是设计使然。

新的处理程序旨在设置一次并单独放置;它不适用于单个执行线程本地的临时更改。您可以通过创建一个新的处理程序来为自己构建这样的工具,该处理程序将其操作推迟到thread_local您的代码可以设置的变量。但 C++ 新的处理程序特性本身并不适用于此类用例。

现在,可以说这是一项遗留决定。C++98/03的内存模型没有考虑线程的可能性。因此,任何 C++11 之前的线程实现基本上都是自己决定哪些操作是线程安全的,哪些是线程本地的,等等。决定将 new-handler 实现为全局构造的实现与使其成为每个线程的实现一样正确。事实上,实现可能在某个时候选择了全局选项,而 C++11 刚刚采用了它。将其更改为线程本地会破坏人们的代码。

但同时,新处理程序的重点是允许用户更改分配失败的默认处理方式。默认错误处理不是线程局部概念;这是整个程序通用的东西。与终止函数等非常相似,恰好有一个预期会被使用。

简而言之,使用类本地新处理程序的代码在某种程度上总是错误的,即使在 C++98/03 时代也是如此。只是在 C++11 标准化线程之前,它是你可以摆脱的(至少就标准而言)。并且它不会被弃用,因为它对其预期目的很有用。nothrow只在本地有用;set_new_handler在全球范围内有用。


推荐阅读