찾다

 >  Q&A  >  본문

关于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++为什么会有这种处理?
书上未能找到相关答案,网上搜寻也没能获得满意答案!

阿神阿神2883일 전952

모든 응답(4)나는 대답할 것이다

  • 怪我咯

    怪我咯2017-04-17 15:36:42

    질문 1

    g 환경에서 컴파일할 때 오류가 발생했습니다: 일치하는 방법이 없습니까?

    오류가 발생하는 이유는 복사 생성자의 매개변수 유형이 잘못 작성되었고 const 수정자가 누락되었기 때문입니다. C 에서는 임시 변수를 상수가 아닌 참조에 바인딩할 수 없습니다. 원본 포스터의 프로그램에서 Point fun() 함수의 반환 값은 임시 변수이고 복사 생성자 Point(Point &p)의 매개 변수는 상수가 아닌 참조이므로 컴파일러는 일치하는 함수가 없음을 나타내는 오류를 보고합니다. . 복사 생성자의 매개변수가 상수 참조로 변경되면 임시 변수가 정상적으로 바인딩될 수 있으므로 컴파일이 통과될 수 있습니다. 예:

    으아아아

    질문 2

    새로 추가된 생성자 메소드가 호출되지 않았으나 결과가 정확합니다. 함수에서 객체를 반환할 때 생성자가 호출되면 어떻게 될까요?

    C 표준에서는 컴파일러가 특정 상황에서 함수 반환 값의 복사/이동 작업을 최적화할 수 있다고 분명히 규정하고 있기 때문입니다.

    ISO C 11 표준 §8.5/16은 다음을 제공합니다(문맥 생략).

    ... 어떤 경우에는 초기화되는 객체에 중간 결과를 직접 구성하여 직접 초기화에 내재된 복사를 제거하는 구현이 허용됩니다. 12.2, 12.8을 참조하세요.

    §12.8/31에는 다음이 있습니다:

    특정 기준이 충족되면 객체의 복사/이동 생성자 및/또는 소멸자에 부작용이 있더라도 구현 시 클래스 객체의 복사/이동 생성을 생략할 수 있습니다 ...

    이것은 단지 컴파일러 최적화일 뿐입니다. 작성자는 Visual Studio의 릴리스 모드를 사용하여 컴파일을 시도할 수 있으며, g 와 같은 복사 생성자를 건너뛰어야 합니다.

    회신하다
    0
  • 高洛峰

    高洛峰2017-04-17 15:36:42

    관련 정보를 참고한 결과 C 표준에 [반환값 최적화]가 있다는 것을 알게 되었습니다.
    gcc/g 가 복사 생성자를 호출하지 않는 이유는 gcc/g 가 관련 연산을 최적화하고 불필요한 복사 연산을 생략했기 때문입니다. 구체적인 설명은 Zhihu에서 누군가가 제공한 설명을 참조하세요.

    • GCC가 이런 일을 합니다. 구조를 반환해야 하는 함수의 경우 호출 시 추가 주소가 함수에 전달됩니다. 그런 다음 함수는 이 주소에 직접 반환 값을 구성합니다. 이것의 장점은 추가적인 복사 생성 없이 반환 값이 적절한 위치에 직접 생성된다는 것입니다. 불필요한 복사 구성을 피하는 매우 영리한 구현입니다. GCC에 엄지손가락을 치켜세워주세요! !
      저자: 리치마이 링크:https://www.zhihu.com/questio...来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    Visual Studio의 디버그 모드를 릴리스로 변경하고 이러한 불필요한 작업도 최적화된 것을 확인했습니다
    결과
    fun() 호출됨
    x는 2

    그래서 문제가 해결되었습니다.

    회신하다
    0
  • 高洛峰

    高洛峰2017-04-17 15:36:42

    제 기억이 맞다면 C 11이나 C 14는 const 없이 가능하기 때문입니다. 예전에는 필수였지만 사실 이 제한은 의미가 없습니다

    회신하다
    0
  • 大家讲道理

    大家讲道理2017-04-17 15:36:42

    실제로 복사 생성자를 호출한 것이 아니라 t2에 직접 값을 할당했기 때문에 이렇게 복사 생성자를 사용해야 합니다.

    으아아아

    회신하다
    0
  • 취소회신하다