简体   繁体   English

这个C ++静态分析规则是否有意义?

[英]Does this C++ static analysis rule make sense as is?

I'm implementing some C++ static analysis rules, and one of them prohibits a function from returning a reference or pointer to a reference parameter of the function, ie the following are all non-compliant: 我正在实现一些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

The justification given for this is that "It is implementation-defined behaviour whether the reference parameter is a temporary object or a reference to the parameter." 为此给出的理由是“它是实现定义的行为,无论引用参数是临时对象还是对参数的引用”。

I'm puzzled by this, however, because stream operators in C++ are written in this way, eg 然而,我对此感到困惑,因为C ++中的流操作符是以这种方式编写的,例如

std::ostream& operator<<(std::ostream& os, const X& x) {
    //...
    return os;
}

I think I'm pretty confident that stream operators in C++ do not in general exhibit implementation-defined behaviour, so what's going on? 我认为我非常有信心C ++中的流操作符通常不会表现出实现定义的行为,所以发生了什么?

According to my understanding as it is at present, I would expect #1 and #3 to be well-defined, on the basis that temporaries cannot be bound to non-const references, so int& x refers to a real object that has lifetime beyond the scope of the function, hence returning a pointer or reference to that object is fine. 根据我目前的理解,我希望#1和#3能够很好地定义,因为temporaries不能绑定到非const引用,所以int& x指的是一个超出生命周期的真实对象函数的范围,因此返回指向该对象的指针或引用是好的。 I would expect #2 to be dodgy, because a temporary could have been bound to const int& x , in which case trying to take its address would seem a bad plan. 我希望#2是狡猾的,因为临时可能已经绑定到const int& x ,在这种情况下尝试获取其地址似乎是一个糟糕的计划。 I'm not sure about #4 - my gut feeling is that that's also potentially dodgy, but I'm not sure. 我不确定#4 - 我的直觉是,这也可能是狡猾的,但我不确定。 In particular, I'm not clear on what would happen in the following case: 特别是,我不清楚以下情况会发生什么:

const int& m(const int& x) { return x; }
//...
const int& r = m(23);

As you say, #1 and #3 are fine (though #1 is arguably bad style). 正如你所说,#1和#3都很好(虽然#1可以说是糟糕的风格)。

#4 is dodgy for the same reason #2 is; #4是出于同样的原因而狡猾#2是; it allows propagating a const reference to a temporary past its lifetime. 它允许将const引用传播到其生命周期的临时值。

Let's check: 让我们检查:

#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";
}

This outputs: 这输出:

C()
~C()
c in scope

In C++11, #2 and #4 can be made safe if there are also rvalue reference overloads. 在C ++ 11中,如果还存在右值引用过载,则可以使#2和#4安全。 Thus: 从而:

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.
}

So although they are dodgy, they do have safe uses if the programmer knows what they are doing. 因此,尽管它们很狡猾,但如果程序员知道他们在做什么,它们确实有安全用途。 It'd be draconian to forbid this. 禁止这样做是非常严厉的。

(Perhaps safer would be if the const rvalue reference overload was made private, left undefined, or otherwise caused a compile-time or link-time error. This is especially true for the #4 case, where we return a reference but there is nothing good to return a reference to and the language doesn't allow references to null.) (如果const rvalue引用重载是私有的,未定义的,或者导致编译时或链接时错误,则可能更安全。对于#4情况尤其如此,我们返回引用但没有任何内容很好地返回引用,语言不允许引用null。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM