关于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++为什么会有这种处理?
书上未能找到相关答案,网上搜寻也没能获得满意答案!
怪我咯2017-04-17 15:36:42
g 환경에서 컴파일할 때 오류가 발생했습니다: 일치하는 방법이 없습니까?
오류가 발생하는 이유는 복사 생성자의 매개변수 유형이 잘못 작성되었고 const
수정자가 누락되었기 때문입니다. C 에서는 임시 변수를 상수가 아닌 참조에 바인딩할 수 없습니다. 원본 포스터의 프로그램에서 Point fun()
함수의 반환 값은 임시 변수이고 복사 생성자 Point(Point &p)
의 매개 변수는 상수가 아닌 참조이므로 컴파일러는 일치하는 함수가 없음을 나타내는 오류를 보고합니다. . 복사 생성자의 매개변수가 상수 참조로 변경되면 임시 변수가 정상적으로 바인딩될 수 있으므로 컴파일이 통과될 수 있습니다. 예:
새로 추가된 생성자 메소드가 호출되지 않았으나 결과가 정확합니다. 함수에서 객체를 반환할 때 생성자가 호출되면 어떻게 될까요?
C 표준에서는 컴파일러가 특정 상황에서 함수 반환 값의 복사/이동 작업을 최적화할 수 있다고 분명히 규정하고 있기 때문입니다.
ISO C 11 표준 §8.5/16은 다음을 제공합니다(문맥 생략).
... 어떤 경우에는 초기화되는 객체에 중간 결과를 직접 구성하여 직접 초기화에 내재된 복사를 제거하는 구현이 허용됩니다. 12.2, 12.8을 참조하세요.
§12.8/31에는 다음이 있습니다:
특정 기준이 충족되면 객체의 복사/이동 생성자 및/또는 소멸자에 부작용이 있더라도 구현 시 클래스 객체의 복사/이동 생성을 생략할 수 있습니다 ...
이것은 단지 컴파일러 최적화일 뿐입니다. 작성자는 Visual Studio의 릴리스 모드를 사용하여 컴파일을 시도할 수 있으며, g 와 같은 복사 생성자를 건너뛰어야 합니다.
高洛峰2017-04-17 15:36:42
관련 정보를 참고한 결과 C 표준에 [반환값 최적화]가 있다는 것을 알게 되었습니다.
gcc/g 가 복사 생성자를 호출하지 않는 이유는 gcc/g 가 관련 연산을 최적화하고 불필요한 복사 연산을 생략했기 때문입니다. 구체적인 설명은 Zhihu에서 누군가가 제공한 설명을 참조하세요.
GCC가 이런 일을 합니다. 구조를 반환해야 하는 함수의 경우 호출 시 추가 주소가 함수에 전달됩니다. 그런 다음 함수는 이 주소에 직접 반환 값을 구성합니다. 이것의 장점은 추가적인 복사 생성 없이 반환 값이 적절한 위치에 직접 생성된다는 것입니다. 불필요한 복사 구성을 피하는 매우 영리한 구현입니다. GCC에 엄지손가락을 치켜세워주세요! !
저자: 리치마이 링크:https://www.zhihu.com/questio...来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Visual Studio의 디버그 모드를 릴리스로 변경하고 이러한 불필요한 작업도 최적화된 것을 확인했습니다
결과
fun() 호출됨
x는 2
그래서 문제가 해결되었습니다.