关于c++的拷贝构造函数.
书中写到:
在C++中,下面三种对象需要调用拷贝构造函数!
对象以值传递的方式传入函数参数
对象以值传递的方式从函数返回
对象需要通过另外一个对象进行初始化;
针对上面的第二条,按照书中例子写出如下代码:
#include <iostream>
using namespace std;
class Point
{
public:
Point(int xx = 0, int yy = 0) :x(xx),y(yy){}
Point(Point &p){
x = p.x;
y = p.y;
cout << "copy function is Called" << endl;
}
int GetX(){ return x; }
int GetY(){ return y; }
private:
int x, y;
};
Point fun()
{
cout << "fun() Called\n";
Point t(2, 2);
return t;
}
int main()
{
Point t1(1,1);
Point t2 = fun();
cout << t2.GetX()<< endl;;
}
以上代码能在visual studio 2013 环境 下顺利编译通过
输出为
fun() Called
copy function is Called
x is 2
当在g++环境下编译时,却出现了错误
C:\Users\Hale\Desktop\test1>g++ -std=c++11 test22.cpp -o test22
test22.cpp: In function 'int main()':
test22.cpp:30:17: error: no matching function for call to 'Point::Point(Point)'
Point t2 = fun();
^
test22.cpp:30:17: note: candidates are:
test22.cpp:8:2: note: Point::Point(Point&)
Point(Point &p){
^
test22.cpp:8:2: note: no known conversion for argument 1 from 'Point' to 'Point&'
test22.cpp:7:2: note: Point::Point(int, int)
Point(int xx = 0, int yy = 0) :x(xx),y(yy){}
^
test22.cpp:7:2: note: no known conversion for argument 1 from 'Point' to 'int'
C:\Users\Hale\Desktop\test1>g++ -std=c++11 test22.cpp -o test22
test22.cpp:8:15: error: invalid constructor; you probably meant 'Point (const Point&)'
Point(Point p){
^
没有匹配的方法?于是添加构造函数
Point(const Point &p){
x = p.x;
y = p.y;
cout << "const copy function is Called" << endl;
}
再次编译,成功!
结果如下
fun() Called
2
但是刚刚新增的构造方法的方法并没有被调用,但是结果是正确的。说好的作为函数返回对象会调用构造函数呢?
g++为什么会有这种处理?
书上未能找到相关答案,网上搜寻也没能获得满意答案!
Question 1
The reason for the error is that the parameter type of your copy constructor is incorrectly written, and the
const
modifier is missing. In C++, temporary variables cannot be bound to non-const references. The return value of the functionPoint fun()
in the original poster's program is a temporary variable, and the parameters of the copy constructorPoint(Point &p)
are non-const references, so the compiler will report an error, indicating that there is no matching function. When the parameters of the copy constructor are changed to constant references, the temporary variables can be bound normally, so the compilation can pass. For example:Question 2
This is because the C++ standard clearly stipulates that the compiler can optimize the copy/move operation of function return values under certain circumstances.
The ISO C++11 standard §8.5/16 provides the following (context omitted):
In §12.8/31 there is:
So, this is just a compiler optimization. The author can try to compile using Visual Studio's Release mode, which should skip the copy constructor like g++.
After consulting relevant information, I found that there is [Return Value Optimization] in the C++ standard.
The reason why gcc/g++ does not call the copy constructor is because gcc/g++ has optimized related operations and omitted unnecessary copy operations. For a specific explanation, please refer to the explanation given by someone on Zhihu:
GCC does this. For any function that needs to return a structure, an additional address will be passed to the function when it is called. The function then constructs the return value directly to this address. The advantage of this is that the return value is directly constructed in the appropriate place, without the need for additional copy construction. It is a very clever implementation that avoids unnecessary copy construction. Give GCC a thumbs up! !
Author: Li Qimai Link: https://www.zhihu.com/questio... Source: Zhihu copyright belongs to the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
Changed the Debug mode of visual studio to Release and found that these unnecessary operations were also optimized
Results
fun() Called
x is 2
So the problem is solved.
If I remember correctly, it’s because C++11 or C++14 can do without const. It was required before, but in fact this restriction is meaningless
Because you did not actually call the copy constructor, but directly assigned a value to t2, you should use the copy constructor like this.