编译器的差异:临时对象做实参的可能编译不过?

kubobo 2007-04-23 11:06:12
下面的代码在vs2005可正常编译运行,但gcc似乎不行(偶用的cygwin),虽然vs2005对标准C++的支持已经有很大进步了。。

gcc版本如下:

D:\cygwin\bin>gcc -v
Reading specs from /usr/lib/gcc/i686-pc-cygwin/3.4.4/specs
Configured with: /gcc/gcc-3.4.4/gcc-3.4.4-1/configure --verbose --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --lib
dir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,ada,c++,d,f77,
java,objc --enable-nls --without-included-gettext --enable-version-specific-runtime-libs --without-x --enable-libgcj --d
isable-java-awt --with-system-zlib --enable-interpreter --disable-libgcj-debug --enable-threads=posix --enable-java-gc=b
oehm --disable-win32-registry --enable-sjlj-exceptions --enable-hash-synchronization --enable-libstdcxx-debug : (reconfi
gured)
Thread model: posix
gcc version 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)



言归正传,

问题一:

void fun2(string &str)
{
cout << str << endl;
}

int main()
{
fun2(string("hello, "));
}

gcc编译错误提示如下:
D:\cygwin\home\ADMINI~1\project\aboutCPP.cpp: In function `int main()':
D:\cygwin\home\ADMINI~1\project\aboutCPP.cpp:35: error: invalid initialization of non-const reference of type 'std::string&' from a temporary of type 'std::string'
D:\cygwin\home\ADMINI~1\project\aboutCPP.cpp:28: error: in passing argument 1 of `void fun2(std::string&)'

为什么非法?看起来似乎是由于临时对象是一个const对象?真的吗?

答案是否定的,下面的代码可以说明之:

class MyString
{
public:
int Data() { return m_data; }
MyString &Data(int val) { m_data = val; }
private:
int m_data;
};

int main()
{
cout << MyString().Data(2).Data() << endl;
}

说明临时对象是non-const的!

另外,无意中又发现一个问题。

问题二:

class MyString
{
public:
int Data() { return m_data; }
MyString &Data(int val) { m_data = val; }
private:
int m_data;
};

int main()
{
MyString conMyStr;
const MyString conMyStr2;
}

gcc编译报错如下:
D:\cygwin\home\ADMINI~1\project\aboutCPP.cpp: In function `int main()':
D:\cygwin\home\ADMINI~1\project\aboutCPP.cpp:51: error: uninitialized const `conMyStr2'

gcc对const的支持有问题吗(瞎猜的,怎可能)?这个错又怎么解释?

小弟比较穷,分不多,但暂时也找不到好的解释办法。

哪位大侠可指点一下,谢谢~!
...全文
541 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
kubobo 2007-04-29
  • 打赏
  • 举报
回复
大家讨论这么多,确实很有收获,我的理解是:

1. 为了防止给常量或临时变量(只有瞬间的生命周期)赋值,只许使用const引用之。

2. 编译器构造的trivial构造函数不足以对const对象初始化,因为为const对象初始化是程序员的责任

分我也不知道怎么给好,总之给了回帖中对我有帮助的兄弟,谢谢大家~!
Jofee 2007-04-27
  • 打赏
  • 举报
回复
我没有理解你说的意思。
我的理解只是对
const double& cdr = 1; // ok
为什么被解释成
double temp = double(1) ; // first create a temporary with the right value
const double& cdr = temp; // then use the temporary as the initializer for cdr
的进一步说明。

总之整个这段话的目的就是说:
临时变量不能放在非const引用上,
而可以放在const引用上。

临时变量是相对于作用域来说的。
Jofee 2007-04-26
  • 打赏
  • 举报
回复
关于标准的解释
Initialization of a reference is trivial when the initializer is an
lvalue (an object whose address you can take; see §4.9.6). The
initializer for a 'plain' T& must be an lvalue of type T. The
initializer for a const T& need not be an lvalue or even of type T.
In such cases (David''s notes: and only in such cases),
[1] first, implicit type conversion to T is applied if necessary (see §C.6);
[2] then, the resulting value is placed in a temporary variable of type T; and
[3] finally, this temporary variable is used as the value of the initializer.
Consider:
double& dr = 1; // error: lvalue needed
const double& cdr = 1; // ok
The interpretation of this last initialization might be:
double temp = double(1) ; // first create a temporary with the right value
const double& cdr = temp; // then use the temporary as the initializer for cdr
A temporary created to hold a reference initializer persists until
the end of its reference’s scope.
References to variables and references to constants are distinguished
because the introduction of a temporary in the case of the variable
is highly errorprone;
an assignment to the variable would become an assignment to the –
soon to disappear – temporary. No such problem exists for references
to constants, and references to constants are often important as
function arguments (§11.6).
dai_weitao 2007-04-26
  • 打赏
  • 举报
回复
看来问题已经解答了.
我说一下解决方法吧:
1` 在参数上加上const.
2` 没有初始化,因为没有自己的构造函数,默认构造函数不做任何初始化工作.
oyd 2007-04-26
  • 打赏
  • 举报
回复
另外,我认为Jofee(阿飞) 没看出来其合理性,尤其是"因为这时这个临时对象会被编译器修改为静态的或者全局的等等"这一句更是匪夷所思。

to kubobo(酷波波) :
我认为我的例子恰恰就是C++标准为何"规定:非常量的引用不能指向临时对象"的原因
你如果认为
char a[] = "hello, ";
assign(a, "world!");
看不出什么意义,那么你试试:
int a = 10;
set_float(a, 20.0);
这里set_float如果能编译过去的话,那么结果a的值还是10,你不觉得类似这样的代码会严重扰乱视听吗?

C++是一个强类型的语言,其设计宗旨之一就是用类型系统把许多Bug扼杀在编译期间。
oyd 2007-04-26
  • 打赏
  • 举报
回复
对于楼主的这个例子:
int main()
{
MyString conMyStr;
const MyString conMyStr2;
}
你不妨改成理解一下:
int main()
{
int a;// ok
const int b; // error
}
taodm 2007-04-26
  • 打赏
  • 举报
回复
你那个类根本就没有默认构造函数,不是const版本不能调默认构造函数。
不要跟我说“编译器不是会自动生成一个的吗”之类,这话不正确,编译器只在一定条件下才自动生成一个,具体去看Effecitve C++。
jixingzhong 2007-04-26
  • 打赏
  • 举报
回复
事情总得在一定的基础准则上开展吧?
Jofee 2007-04-26
  • 打赏
  • 举报
回复
确实属于C++标准的规定:非常量的引用不能指向临时对象,
原因很明显避免临时对象销毁之后引用无效。

对于常量的引用,是可以指向临时对象的,
因为这时这个临时对象会被编译器修改为静态的或者全局的等等,
反正就是使这个临时对象的生命周期延长。

kubobo 2007-04-26
  • 打赏
  • 举报
回复
to oyd:

抱歉,这个例子有意义吗。。
kubobo 2007-04-26
  • 打赏
  • 举报
回复
to taodm:

1. C++标准哪条有规定?如果没有合理的理由为何限制,所以这个并不是我想要的答案。。

2. MyString conMyStr;
const MyString conMyStr2;
taodm是否认为后者没有调用了默认构造函数?前者应该调用了吧,那么你的意思是说后者加了const就不能调用了吗?
还是谢谢你的回复~
oyd 2007-04-26
  • 打赏
  • 举报
回复
to Jofee(阿飞) ,请注意这一段的理解:

because the introduction of a temporary in the case of the variable
is highly errorprone;
an assignment to the variable would become an assignment to the –
soon to disappear – temporary. No such problem exists for references
to constants

第一句说的易出错指的是逻辑错误,而不是“临时对象销毁之后引用无效”,如果我没记错的话,C++中不存在无效引用。出了作用域,临时对象与引用一同消失。
这里第二句是关键:向一变量赋值可能导致赋值到一个马上就要消失的临时变量上去,而对于常量引用不存在这个问题。
很明显,问题就在于,向一个马上就要消失的变量赋值没有起到期望的作用,常量引用没问题是因为常量引用不允许赋值。
oyd 2007-04-24
  • 打赏
  • 举报
回复
假设你的代码是这样写的
void assign(string &str, const char* s)
{
str = s;
}

int main()
{
char a[] = "hello, ";
assign(a, "world!");
}
那么这样的代码被编译通过后,用户会很疑惑:a的值看似改了,实际上没有被改动。
taodm 2007-04-23
  • 打赏
  • 举报
回复
C++标准规定:非const的引用不能加在临时变量上。
规定!仅此而已。

变量没有初始化,编译器加强为error也无可厚非。给你的MyString加上默认构造函数。

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧