Stu*_*etz 12 c++ reference language-lawyer reference-binding
我正在实现一些C++静态分析规则,其中一个规则禁止函数返回引用或指向函数引用参数的指针,即以下都是不兼容的:
int *f(int& x) { return &x; } // #1
const int *g(const int& x) { return &x; } // #2
int& h(int& x) { return x; } // #3
const int& m(const int& x) { return x; } // #4
Run Code Online (Sandbox Code Playgroud)
为此给出的理由是"它是实现定义的行为,无论引用参数是临时对象还是对参数的引用."
然而,我对此感到困惑,因为C++中的流操作符是以这种方式编写的,例如
std::ostream& operator<<(std::ostream& os, const X& x) {
//...
return os;
}
Run Code Online (Sandbox Code Playgroud)
我认为我非常有信心C++中的流操作符通常不会表现出实现定义的行为,所以发生了什么?
根据我目前的理解,我希望#1和#3能够很好地定义,因为temporaries不能绑定到非const引用,所以int& x指的是一个超出范围的实际对象函数,因此返回指向该对象的指针或引用是好的.我希望#2变得狡猾,因为一个临时的本来可以被束缚const int& x,在这种情况下,试图取其地址似乎是一个糟糕的计划.我不确定#4 - 我的直觉是,这也可能是狡猾的,但我不确定.特别是,我不清楚以下情况会发生什么:
const int& m(const int& x) { return x; }
//...
const int& r = m(23);
Run Code Online (Sandbox Code Playgroud)
正如你所说,#1和#3都很好(虽然#1可以说是糟糕的风格).
#4是出于同样的原因而狡猾#2是; 它允许将const引用传播到其生命周期的临时值.
让我们检查:
#include <iostream>
struct C {
C() { std::cout << "C()\n"; }
~C() { std::cout << "~C()\n"; }
C(const C &) { std::cout << "C(const C &)\n"; }
};
const C &foo(const C &c) { return c; }
int main() {
const C &c = foo(C());
std::cout << "c in scope\n";
}
Run Code Online (Sandbox Code Playgroud)
这输出:
C()
~C()
c in scope
Run Code Online (Sandbox Code Playgroud)