2012-07-18 106 views
12

我实施一些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++中的流操作符是用这种方式编写的,例如,

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

我觉得我非常有信心,在C++流运营商在普遍表现出实现定义的行为没有,所以这是怎么回事?

根据我目前的理解,我期望#1和#3是明确的,因为临时不能绑定到非const引用,所以int& x指的是一个真实的对象,具有超出函数范围的生命期,因此返回指向该对象的指针或引用就没有问题。我预计#2会变得狡猾,因为临时可能会被绑定到const int& x,在这种情况下,试图采用它的地址似乎是一个糟糕的计划。我不清楚#4 - 我的直觉是,这也可能是狡猾的,但我不确定。特别是,我不是在以下情况下会发生什么明确:

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

您正在使用MSVC++吗? – Nawaz 2012-07-18 09:44:38

+0

@Nawaz:我使用.QL在大型代码库中编写查询:)我不认为这应该关系到什么编译器,我理想的是寻找平台无关的答案。 – 2012-07-18 09:47:23

+2

为什么我问,因为MSVC++提供了允许临时绑定到非const引用的编译器扩展。如果您使用的是Microsoft静态分析工具,那么它也可能会考虑此扩展。 – Nawaz 2012-07-18 09:48:53

回答

8

正如你所说,#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"; 
} 

此输出:

C() 
~C() 
c in scope 
+0

谢谢 - 我不确定临时工的生命是否会因为做这种事情而延长。似乎答案是一个公司'不',ta。 – 2012-07-18 09:49:08

+0

以及流操作符? – Arne 2012-07-18 09:59:45

+3

@Arne:他们接受并返回一个非const引用,所以他们很好。 – 2012-07-18 10:02:48

1

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

所以虽然他们是狡猾的,但如果程序员知道他们在做什么,他们确实有安全的用途。禁止这种做法是严厉的。如果const rvalue引用重载被设置为private,left undefined,或者导致编译时或链接时错误,那么安全的做法可能更安全。对于#4情况尤其如此,我们返回一个引用但是返回引用并没有什么好处,并且语言不允许引用null)。

+0

谢谢,好点,特别是对未来。其中的背景是,我正在为我们的商业工具实施相当严格的规则 - 他们被一个标准固定下来,所以我必须小心偏离规则的字母。这就是说,目标是尽可能减少误报。我们还不支持C++ 11,但是当我们这样做时,我肯定会修改规则来考虑右值引用超载。 – 2012-07-24 22:19:39

+0

返回对右值参数的引用是“安全”的情况之一是使用'std :: move'和'std :: forward',它们都可能带有右值参数。 IOW,如果你打算把这样一个函数的结果直接传递给另一个表达式,无论它是哪一个(像另一个函数)。 – Xeo 2012-07-26 02:02:45

相关问题