使用 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】:
&x
和 std::addressof(x)
之间的区别(对于类类型的变量)只有在 x
具有重载的 &
运算符时才会出现。
addressof
的意思是“不,不,我真的想要这东西的地址,不管班级设计者有什么规定”。
话虽如此,99++% 的时间&x
都很好。 cout
肯定没问题,因为您可以查看并看到它没有 operator &
。
【讨论】:
以上是关于使用 std::addressof(std::cout) 代替 &std::cout 有啥风险吗?的主要内容,如果未能解决你的问题,请参考以下文章
为啥不能从 std::addressof<int> 解析模板参数?