现在的位置: 首页 > 综合 > 正文

gcc 3.3.4中使用引用时存在的问题

2013年10月06日 ⁄ 综合 ⁄ 共 2259字 ⁄ 字号 评论关闭

2011-11-1 wcdj

问题:
rvalue类型表达式可以有引用吗?

const int &iref = 100;
printf("%d", iref);// ok, 100

rvalue类型表达式可以有non-const的引用吗?

标准参考:
C++ 03 3.10 Lvalues and rvalues P.56
1, Every expression is either an lvalue or an rvalue. 表达式的属性,非对象的属性。
6, An expression which holds a temporary object resulting from a cast to a nonreference type is an rvalue (this includes the explicit creation of an object using functional notation (5.2.3)). 临时对象是右值。
8.3.2 References

测试代码:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
	int i = 1;
	int &i_ref = i;// ok, lvalue
	printf("i = %d\n", i_ref);

	// check lvalue
	/*
	int *i_p = &i; 
	unsigned int *u_i_p = &((unsigned int)i);// error,  '&' requires l-value
	*/

	unsigned int &u_i_ref = (unsigned int)i;// error ? the temporary object is an rvalue
	printf("i = %u\n", u_i_ref);

	return 0;
}

几种编译方法:
(1) gcc -lstdc++ -o ref ref.cpp
(2) g++ -o ref ref.c
(3) g++ -o ref ref.cpp

分别在不同的编译器下测试结果如下:

(1) gcc 3.3.4 没有报错输出

i = 1
i = 1
下面代码可以说明gcc 3.3.4中的问题:

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int i = 1;
	int& ref = i;// ok, lvalue
	printf("i = %d\n", ref);

	unsigned int &u_i_ref = (unsigned int)i;// ok, gcc 3.3.4
	printf("i = %u\n", u_i_ref);

	u_i_ref = 2;
	printf("i = %u\n", u_i_ref);	// 2
	printf("i = %u\n", i);		// 1

	return 0;
}

使用不当就会存在这样的漏洞:
本意是想通过引用,调用fun函数来修改变量i的值,但是实际上fun实参和形参已经不是一个变量,因此调用完fun函数后,变量i的值并没有改变。这样在业务逻辑上就可能出现问题。

#include <stdio.h>
#include <stdlib.h>

void fun(unsigned int &uiPara)
{
    uiPara = 100;// modify
}

int main(int argc, char* argv[])
{
    int i = 1;
    int& ref = i;// ok, lvalue
    printf("i = %d\n", ref);// 1
    fun((unsigned int)i);     
    printf("i = %d\n", i);// 1

    return 0;
}

应对上述问题,在gcc 3.3.4中正确的做法应该是:

#include <stdio.h>
#include <stdlib.h>

void fun(unsigned int &uiPara)
{
    uiPara = 100;// modify
}

int main()
{
    int i = 1;
    int& ref = i;// ok, lvalue
    printf("i = %d\n", ref);// 1
    fun((unsigned int)i); 
    printf("i = %d\n", i);// 1, sorry, it's not we want
    
     // ok
    unsigned int j = 1;
    printf("j = %d\n", j);// 1
    fun(j); 
    printf("j = %d\n", j);// 100, that's ok!

    return 0;
}

(2) gcc 4.1.2 报错

error: invalid initialization of non-const reference of type 'unsigned int&' from a temporary of type 'unsigned int'
改为:

	const unsigned int &u_i_ref = (unsigned int)i;// ok
	const unsigned int &u_i_ref = (unsigned int)i_ref;// ok

(3) VS2010 报错

error C2440: 'initializing' : cannot convert from 'unsigned int' to 'unsigned int &'
改为:

	const unsigned int &u_i_ref = (unsigned int)i;// ok
	const unsigned int &u_i_ref = (unsigned int)i_ref;// ok

结论:
强制类型转换会产生一个临时对象(右值),gcc3.3.4允许这个临时对象具有no-const的相应类型的引用。而gcc4.1.2和VS2010要求对右值的引用必须是const引用。安全的做法是:不要对临时对象使用引用。

int tmp = 100;
unsigned int &iref = (unsigned int)tmp; // ok, gcc3.3.4

抱歉!评论已关闭.