编译器在 const ref 类型参数上使用临时对象时是否应该警告不安全的行为?
Should compiler warn about unsafe behaviour when using temporary object on const ref type parameters?
让我们考虑以下不正确的代码:
#include <string>
#include <iostream>
struct C {
C(const std::string &_s): s(_s) { }
void run() {
std::cout << "Here we are using the string " << s << "n";
}
const std::string &s;
};
int main() {
C a("/tmp/example.log");
a.run();
return 0;
}
g++ 6.3.0 作为 clang 3.8.1 编译此代码时没有警告,即使使用-W -Wall -Werror
,但即使对于粗心的程序员来说,这种行为也只是说这里出了点问题:
Here we are using the string Here we are usin
为什么结果不像人们天真期望的那样?从const char *
创建std::string
对象的生存期仅限于构造函数的范围。因此,当构造函数返回foo()
时,foo::s
字段具有对不存在对象的引用。卡布姆。
如果有人理解这个想法,就很容易引入修复程序。它可以是显式创建std::string
对象并将其作为参数传递:
std::string s("/tmp/example.log");
C a(s);
另一个,我认为更安全一点的是将foo::s
字段声明更改为:
const std::string s;
创建参数的本地不可修改副本,但它会增加复制对象的成本。好吧,在这个例子中,复制 std::string 不会自动导致进行深度复制,但对于自己实现的类来说,这可能是完全不同的事情。
对于 C++11,很少有其他方法可用,如本答案中所述,但是 - 例如 - 在嵌入式 Linux 环境中,当您坚持使用旧的编译器和一些遗留代码时,它不一定是一个相当大的选择。
但是,无论程序员选择哪种解决方案,都必须知道存在问题。即使我正确地编写了代码,我也愚蠢地认为编译器会足够聪明地检测到明显危险的情况,如果其他开发人员陷入传递const char *
参数的陷阱。但是,我决定编写一些代码来检查编译器的行为,我很失望 - 很容易陷入引用已经不存在的对象的陷阱。
将临时对象作为 const 引用传递是一个公认的危险,并且在 C++11 中以某种方式解决了这个问题,但仍然将积极抵制这种行为的责任转嫁给程序员。那么,期望编译器发出警告是合理的,还是应该依赖外部静态分析工具?
通过设计将临时绑定到常量参考作品,不应发出任何警告。它不是代码中问题的根源。问题是您使用 const 引用作为成员,而不是管理它的正确性。即使您按照建议传递std::string
,这也不能消除问题 - 该字符串必须比您的对象活得更久,您的程序才是正确的。并且创建成员为std::string
或const std::string
并不是更安全,而是在这种情况下安全且适当的方法。在某些情况下,您可能希望将 const 或 non const 引用存储为成员,但您必须了解您正在做什么并确保引用不会悬而未决。编译器不太可能检测到极端情况并在这种情况下发出警告。
IMO 的问题不是将临时对象作为 const 引用传递,而是将其存储为常量引用。将成员更改为const std::string s;
(甚至非常量)将解决此问题。
如果计划将其存储为参考,则必须确保对象生存期在外部。事实上,如果不够小心,C++很容易射到自己的腿上。
而且我真的不希望编译器在存储输入参数作为引用时发出警告,即使如果不小心可能会很危险,因为存在有效的用例(即参数生存期超过对象生存期的所有情况,我不想在内部复制它)。
请注意,这同样适用于存储为指针等。
此外,按值传递参数(与 const ref 相反)根本无法解决问题,因为这样的参数作为值复制仍然是临时的,因此当绑定到引用时,当构造函数离开时,它也会消失。
- C++/CLI 和 C#/VB 与不安全和外部有什么区别?
- 问:Apache Arrow 数组生成器不安全追加
- 不安全的 MPI 非阻塞通信示例?
- 有没有一种简单的方法来检查C++中的不安全表达式
- 为什么静态向下转换unique_ptr不安全?
- 智能感知 PCH 警告不会消失
- 哪些整数操作不安全
- [[maybe_unused]] 在成员变量上,GCC 警告(不正确?)该属性被忽略
- 为什么这个递归 lambda 函数不安全?
- 解决方法:QPixmap:在GUI线程之外使用pixmap是不安全的
- MSVC C6029 警告:缓冲区可能溢出,使用未经检查的值.检查缓冲区大小时,警告不会消失
- 正在匹配不安全的正则线程
- 如何修复编译错误"此函数或变量可能不安全"(strcpy)
- 编译器在 const ref 类型参数上使用临时对象时是否应该警告不安全的行为?
- 实现没有不安全服务器凭据的自定义 AuthMetadataProcessor
- 什么时候关闭__strict_ansi__标志是不安全的
- 原子对象在普通对象安全的任何上下文中都是不安全的
- OpenSSL:将不安全的BIO提升为安全
- 为什么编译器在我定义_CRT_SECURE_NO_WARNINGS之后仍然警告我不安全的strtok
- xxx和bool在操作中的不安全混合仅在将值与TRUE进行比较时发出警告