这是C++;静态分析规则是否有意义? 我正在实施一些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

这是C++;静态分析规则是否有意义? 我正在实施一些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,c++,reference,language-lawyer,reference-binding,C++,Reference,Language Lawyer,Reference Binding,对此给出的理由是“无论引用参数是临时对象还是对参数的引用都是实现定义的行为。” 我对此感到困惑,因为C++中的流操作符是用这种方式编写的,例如 std::ostream& operator<<(std::ostream& os, const X& x) { //... return os; } 正如你所说,#1和#3很好(尽管#1可以说是糟糕的风格) #4是出于同样的原因而狡猾的#2是;它允许将常量引用传播到超过其生存期的临时对象 让我们检查

对此给出的理由是“无论引用参数是临时对象还是对参数的引用都是实现定义的行为。”

我对此感到困惑,因为C++中的流操作符是用这种方式编写的,例如

std::ostream& operator<<(std::ostream& os, const X& x) {
    //...
    return os;
}
正如你所说,#1和#3很好(尽管#1可以说是糟糕的风格)

#4是出于同样的原因而狡猾的#2是;它允许将常量引用传播到超过其生存期的临时对象

让我们检查一下:

#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";
}
在C++11中,如果还存在右值引用重载,则可以使#2和#4安全。因此:

const int *get( const int &x ) { return &x; }
const int *get( const int &&x ) { return nullptr; }

void test() {
    const int x = 0;
    const int *p1 = get( x ); // OK; p1 is &x.
    const int *p2 = get( x+42 ); // OK; p2 is nullptr.
}
因此,尽管它们是不可靠的,但如果程序员知道它们在做什么,它们确实有安全的用途。禁止这样做是很严厉的


(如果常量值引用重载被设置为私有、未定义或以其他方式导致编译时或链接时错误,则可能更安全。对于#4情况尤其如此,在这种情况下,我们返回一个引用,但返回一个引用没有什么好处,而且语言不允许引用为null。)

@Nawaz:我正在使用.QL编写大型代码基上的查询:)我认为使用哪种编译器并不重要,我正在寻找一个与平台无关的理想答案。之所以问这个问题,是因为MSVC++提供了编译器扩展,允许临时对象绑定到非常量引用。如果你使用微软静态分析工具,那么它也可以考虑这个扩展。@纳瓦兹:啊,对了,在这种情况下,我应该为VC++提供一个可选的扩展规则。谢谢(我不得不说,我一般不喜欢这样的编译器扩展。)我没有使用Microsoft静态分析工具,这是一个内部工具-但听起来我需要在其中添加一些特定于Microsoft的内容。您可以通过添加
/Za
(禁用语言扩展)来禁用绑定谢谢-我不确定做这种事是否会延长临时工的寿命。似乎答案是肯定的“不”,ta。那么流操作员呢?@Arne:他们接受并返回一个非常量引用,所以他们很好。谢谢,很好的观点,特别是对于未来。这里的背景是,我正在为我们的商业工具实施一个相当严格的规则集——它们被一个标准所束缚,所以我必须小心,不要偏离规则的文字太远。这就是说,目的是尽可能减少误报。我们还不支持C++11,但当我们支持C++11时,我肯定会倾向于修改规则以考虑右值引用重载。向右值参数返回引用是“安全”的情况之一是使用
std::move
std::forward
,这两种情况都可能使用右值参数。注意,如果您计划将这样一个函数的结果直接传递给另一个表达式,无论它是什么(像另一个函数)。
C()
~C()
c in scope
const int *get( const int &x ) { return &x; }
const int *get( const int &&x ) { return nullptr; }

void test() {
    const int x = 0;
    const int *p1 = get( x ); // OK; p1 is &x.
    const int *p2 = get( x+42 ); // OK; p2 is nullptr.
}