使用 std::addressof(std::cout) 代替 &std::cout 有啥风险吗?

Posted

技术标签:

【中文标题】使用 std::addressof(std::cout) 代替 &std::cout 有啥风险吗?【英文标题】:is there any risk using std::addressof(std::cout) instead of &std::cout?使用 std::addressof(std::cout) 代替 &std::cout 有什么风险吗? 【发布时间】:2020-05-28 21:46:50 【问题描述】:

我正在使用std::cout 进行日志记录,并且当“不要获取 'cout' 的地址,而是从 lambda 调用它”时,sonarqube 会报告错误。

std::ostream *streamp;
streamp = &std::cout;

当我使用下面的代码时,在 sonarqube 中没有观察到错误。在std::cout 函数上使用std::addressof 是否安全?

std::ostream *streamp;
streamp = std::addressof(std::cout);

【问题讨论】:

安全性和使用&一样;分析仪不够聪明,无法看到发生了什么。我想知道这个警告的原因是什么...... 这是一个非常奇怪的警告。 cout 是一个静态对象,保证在您的任何代码之前被初始化,因此获取指向它的指针应该是 100% 安全的。 我怀疑这是一个试图捕捉 [&std::cout]() cout << "Capturing a name unnecessarily"; 等的警告。 @NathanOliver 如果静态对象在关机期间进行日志记录并且cout 在记录器销毁之前被销毁,那么可能会出现问题? @M.M 我认为这不会发生:timsong-cpp.github.io/cppwp/… 【参考方案1】:

是的,在 std::cout 上使用 addressof 是安全的。但是由于在std::cout 上使用& 同样安全,所以这样做的唯一原因是让一个明显给你误报的工具安静下来(它没有意识到addressof 在做什么) .

最好使用& 并使用工具中存在的任何机制来关闭误报。

【讨论】:

【参考方案2】:

std::cout 是一个对象,而不是一个函数,因此禁止获取大多数标准函数地址的规则不适用。

std::addressof() 仅在地址运算符可能超载的情况下才需要(通常甚至考虑都是一件坏事),因此在模板中使用以避免意外。任何标准类型都不需要它,因此也不需要它。

总之,修复工具或忽略该警告,这是您的选择,但不要将您的代码弯曲成椒盐卷饼。


为了扩展标准函数,标准库中的大多数函数都没有被指定为“可寻址”。 因此,获取它们的地址可能会导致意外,从偶然的“工作”,到提供具有意外签名的函数指针(更多参数,意外调用约定,等等),到根本无法编译。这可能会随着工具链的任何变化而改变。

【讨论】:

我同意你的一般分析,但实际上是不是既然std::cout是一个对象,我们就不用担心取地址了?原则上它可能有一个重载的& 运算符,尽管我的猜测(?)是标准不允许这样做? @templatetypedef 澄清了标准类型在这方面是合理的。【参考方案3】:

&xstd::addressof(x) 之间的区别(对于类类型的变量)只有在 x 具有重载的 & 运算符时才会出现。

addressof 的意思是“不,不,我真的想要这东西的地址,不管班级设计者有什么规定”。

话虽如此,99++% 的时间&x 都很好。 cout 肯定没问题,因为您可以查看并看到它没有 operator &

【讨论】:

以上是关于使用 std::addressof(std::cout) 代替 &std::cout 有啥风险吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能从 std::addressof<int> 解析模板参数?

std::bind 与 std::function 与 Clang 崩溃

C++学习(四八零)noskipws skipws

C++ 双重释放或损坏(出)

为啥我的字符串没有被打印?

标准库中聚合可初始化性的类型特征?