Home  >  Q&A  >  body text

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

阿神阿神2714 days ago841

reply all(4)I'll reply

  • 怪我咯

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

    Question 1

    When compiling in g++ environment, an error occurred: No matching method?

    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 function Point fun() in the original poster's program is a temporary variable, and the parameters of the copy constructor Point(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:

    // 给出如下函数声明
    int f();
    void g1(int &i);
    void g2(const int &i);
    int n = 1;
    
    // 则调用结果为
    g1(0);   // compile error
    g1(n);   // ok
    g1(f()); // compile error
    g2(0);   // ok
    g2(n);   // ok
    g2(f()); // ok

    Question 2

    The newly added constructor method was not called, but the result is correct. What if the constructor is called when returning an object from a function?

    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 certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8.

    In §12.8/31 there is:

    When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. ...

    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++.

    reply
    0
  • 高洛峰

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

    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.

    reply
    0
  • 高洛峰

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

    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

    reply
    0
  • 大家讲道理

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

    Because you did not actually call the copy constructor, but directly assigned a value to t2, you should use the copy constructor like this.

    Point t2(fun);

    reply
    0
  • Cancelreply