由一道题目想到的C++编译器优化问题 (一)

2014-11-24 12:15:12 · 作者: · 浏览: 4

这两天看到了一个问题,看似简单,但是用的知识着实不少,原题如下:


[cpp]
#include "stdafx.h"

class Base
{
public:
Base(){}
virtual ~Base(){}
Base(const Base &other); // 只声明, 没定义
private:
Base &operator=(const Base &other);
} ;

int _tmain(int argc, _TCHAR* argv[])
{
const Base &b = Base() ; // 为什么没有导致链接错误 应该调用拷贝构造函数才对, 然而我只声明没定义!

return 0;
}
#include "stdafx.h"

class Base
{
public:
Base(){}
virtual ~Base(){}
Base(const Base &other); // 只声明, 没定义
private:
Base &operator=(const Base &other);
} ;

int _tmain(int argc, _TCHAR* argv[])
{
const Base &b = Base() ; // 为什么没有导致链接错误 应该调用拷贝构造函数才对, 然而我只声明没定义!

return 0;
}

我一开始想到的就是编译器优化了:推测下编译器应该做了优化: const Base &b = Base() ;这么写的话,按照语义是:

1.调用Base的构造函数

2.调用Base的赋值函数 b=临时对象但是编译器大概认为没必要这么两步走,直接调用了Base的构造函数。。。。

后面经过大侠A的指导,指出问题所在:

Base b = a 的时候, b 还没有构造, 所以需要先对 b 进行构造, 再紧接着进行赋值, 你说 c++ 编译器的设计者, 能不优化一下么 所以在所有 c++ 规定了这个行为, 即 Base b = a 就是Base
b(a), 这也是 c++ 语法的 sweet.


恩。。。。那么暂时我们就认为const Base &b = Base() ; 被编译器变成了Base b(Base()),那么还是应该会调用默认构造函数和拷贝构造函数啊,可以明明程序并没有报错!!!

关键人物大侠B出现了:


[cpp]
个人以为,const Base &b = Base() ; 引用是直接绑定在右边的那个匿名对象上的,所以木有发生拷贝构造,所以跟拷贝构造函数是否定义木有关系。
参考 ISO/IEC 14882:2003(E)
8.5.3 References
第4 5条款
— Otherwise, the reference shall be to a non-volatile const type (i.e., cv1 shall be const).
个人以为,const Base &b = Base() ; 引用是直接绑定在右边的那个匿名对象上的,所以木有发生拷贝构造,所以跟拷贝构造函数是否定义木有关系。
参考 ISO/IEC 14882:2003(E)
8.5.3 References
第4 5条款
— Otherwise, the reference shall be to a non-volatile const type (i.e., cv1 shall be const). [cpp]
[Example:
double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const
—end example]
— If the initializer expression is an rvalue, with T2 a class type, and “cv1 T1” is reference-compatible with “cv2 T2,” the reference is bound in one of the following ways (the choice is implementation-defined):
— The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.
— A temporary of type “cv1 T2” [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.93)
[Example:
double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const
—end example]
— If the initializer expression is an rvalue, with T2 a class type, and “cv1 T1” is reference-compatible with “cv2 T2,” the reference is bound in one of the following ways (the choice is implementation-defined):
— The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.
— A temporary of type “cv1 T2” [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.93)
看着这么一大堆英文又迷糊了。。。。静下心来好好读了下:

关键在于这段话


[cpp]
— If the initializer expression is an rvalue, with T2 a class type, and “cv1 T1” is reference-compatible with “cv2 T2,” the reference is bound in one of the following ways (the choice is implementation-defined)://如果初始化表达的右边是个类类型,并且左边是一个对右值的常量引用,那么这种情况呢,可以由编译器用以下两种方式实现(两者选一):
— The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.//直接将引用绑定到右值
— A temporary of type “cv1 T2” [sic] is created, and a constructor is called t