c++ - 在 const ref 类型参数上使用临时对象时,编译器是否应该警告不安全行为?

标签 c++ pass-by-const-reference

让我们考虑以下不正确的代码:

#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,几乎没有其他方法可用,如 this answer 中所述,但是 - 例如 - 在嵌入式 Linux 环境中,当您坚持使用旧编译器和一些遗留代码时,它不一定是一个不错的选择。

但是,无论程序员选择何种解决方案,都必须知道存在问题。即使我正确地编写了我的代码,我也愚蠢地假设编译器会足够聪明地检测到这种明显危险的情况,如果其他开发人员会落入传递 const char * 参数的陷阱。然而,我决定编写一些代码来检查编译器的行为,但我很失望——人们很容易陷入引用已经不存在的对象的陷阱。

将临时对象作为 const 引用传递是一种公认​​的危险,它已在 C++11 中以某种方式得到解决,但仍将责任转嫁给程序员以积极抵制这种行为。那么,期望编译器发出警告是否合理,或者应该依赖外部静态分析工具?

最佳答案

临时绑定(bind)到 const 引用作品,不应发出任何警告。它不是您代码中问题的根源。问题是您使用 const 引用作为成员而不是管理它的正确性。即使您按照您的建议传递 std::string ,也不会消除问题 - 该字符串必须比您的对象长寿才能使您的程序正确。将成员创建为 std::stringconst std::string 不仅更安全,而且在这种情况下是安全且正确的方法。在某些情况下,您可能希望将 const 或非 const 引用存储为成员,但您必须了解自己在做什么并确保该引用不会悬空。编译器不太可能检测到极端情况并在这种情况下向您发出警告。

关于c++ - 在 const ref 类型参数上使用临时对象时,编译器是否应该警告不安全行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44568318/

相关文章:

c++ - 难以理解引用定义

c++ - 设计建议 : llvm multiple runtime contexts

c++ - 类构造函数中的 OpenGL sigsegv 错误

c++ - 当 const 引用参数绑定(bind)到右值时,它是否保留其 "status"?

c++ - 我可以让 C++ 编译器决定是按值传递还是按引用传递?

c++ - 如何安全地保留 C++ const 引用?

c++ - 对于从 C++03 枚举到 C++11 枚举类的源向后兼容迁移,这种模式是否可行?

用于将对象流的转换链接在一起的 C++ 设计模式

c++ - 引用 std::thread 参数

c++ - 错误 : ambiguous overload for 'operator=' in swap function using the copy-and-swap idiom