c++ - 为什么可以在 C++ 中使用没有#include 线程的 std::thread ?

标签 c++ windows multithreading

这个问题在这里已经有了答案:





Why does omission of "#include <string>" only sometimes cause compilation failures?

(7 个回答)


1年前关闭。




我尝试了 https://en.cppreference.com/w/cpp/thread/get_id 中的以下代码在visual studio中,注意到它即使没有#include线程也能运行,但不能没有#include mutex(在注释掉使用它的行之后):

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
 
std::mutex g_display_mutex;
 
void foo()
{
    std::thread::id this_id = std::this_thread::get_id();
 
    g_display_mutex.lock();
    std::cout << "thread " << this_id << " sleeping...\n";
    g_display_mutex.unlock();
 
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
int main()
{
    std::thread t1(foo);
    std::thread t2(foo);
 
    t1.join();
    t2.join();
}
我想知道为什么,我在网上找不到解释。互斥锁是否包含线程? IDE的干预?或者是其他东西?

最佳答案

编译器标准库中的头文件之一在内部包含一个定义 std::thread 的头文件。 (在你的情况下,<mutex> 包括这个)。
C++ 标准只保证对任何 #include 可见的定义。 d header ——但它不会控制或阻止实现有意或无意地使其他定义从该 header 可见。
经常发生这种情况是因为您的标准库实现中的 header 已被编写为包含其他内部 header ,这些 header 可传递这些定义(例如 <mutex> 被写入包含 <internal/thread.hpp> 或其他内容)。
依赖这种传递包含是一种非常糟糕的做法,并且会大大降低给定程序的可移植性。如果它们更新了内部包含顺序,这可能会使在不同平台、标准库实现甚至同一编译器的不同版本之间移动变得复杂。

注:重要的是要意识到,仅仅因为一个标准类型可能依赖于另一个头文件中定义的另一个标准类型,它并不能保证这个头文件将被标准库传递包含,除非 C++ 标准实际上规定了这一点(这是非常很少做)。
例如,异常 std::logic_error<stdexcept> 中定义, 并派生出 std::exception定义于 <exception> ;然而 #include <stdexcept>未定义为引入符号 std::exception .一些或大多数标准库实现可能会这样做;但是标准库在内部执行如下所示的间接操作以防止这种情况发生同样是合法的:
<impl/exception.hpp>

namespace std {
  namespace __impl {
     class exception { ... };
  } // namespace __impl 
} // namespace std
<exception>
#include <impl/exception.hpp>

namespace std {
  using __impl::exception;
} // namespace std
<impl/stdexcept.hpp>
#include <impl/exception.hpp>

namespace std {
  namespace __impl {
    class logic_error : public exception { ... }

    /* ... other error types ... */

  } // namespace __impl 
} // namespace std
<stexcept>
#include <impl/stdexcept.hpp>

namespace std {
  // defines 'std::logic_error', and derives 'std::exception', but
  // does not define the symbol 'std::exception' (instead, hides it
  // under std::__impl::exception)
  using __impl::logic_error;

  /* ... other error types ... */

} // namespace std
从上面的例子你可以看到 #include <stdexcept>将定义符号 std::logic_error但不是 std::exception ,尽管这两种类型密切相关。
因此,尽可能遵循 include-what-you-use (IWYU) 实践始终是一个好主意,即使看起来您可能包含了多余的 header 。否则,您可能会将自己修复为当前设置,并为将来的可移植性引入更多复杂性(即使它只是为了升级您的编译器)

关于c++ - 为什么可以在 C++ 中使用没有#include 线程的 std::thread ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63358220/

相关文章:

c# - 自定义保存文件对话框以类似于底层操作系统保存对话框 C#

c++ - WriteFileGather - 将缓冲区附加到文件

Python 线程和 GIL

c++ - 何时调用 QApplication 析构函数

windows - 使用 powershell 在远程计算机上启动 .exe 文件

C++ 在 Vector 中使用不可赋值的对象

c - 线程在不应该阻塞时阻塞

c - C 语言中有 void operator() () 吗?

c++ - |运算符 ,++ 和 I 运算符

c# - 如何使用 MigraDoc 添加书签?