关于C++拷贝构造函数的疑惑

查看:123
本文介绍了关于C++拷贝构造函数的疑惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

关于c++的拷贝构造函数.
书中写到:

  • 在C++中,下面三种对象需要调用拷贝构造函数!

    1. 对象以值传递的方式传入函数参数

    2. 对象以值传递的方式从函数返回

    3. 对象需要通过另外一个对象进行初始化;

针对上面的第二条,按照书中例子写出如下代码:

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

解决方案

问题一

当在g++环境下编译时,却出现了错误:没有匹配的方法?

报错原因是你的拷贝构造函数参数类型写的不对,少了const修饰符。在C++中,临时变量是不能绑定到非常量引用的。而楼主程序中函数Point fun()的返回值是临时变量,拷贝构造函数Point(Point &p)的参数是非常量引用,所以编译器会报错,提示没有匹配的函数。当把拷贝构造函数的参数改成常量引用后,临时变量就可以正常绑定,所以可以编译通过了。例如:

// 给出如下函数声明
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

问题二

刚刚新增的构造方法的方法并没有被调用,但是结果是正确的。说好的作为函数返回对象会调用构造函数呢?

这是因为C++标准中明确规定了编译器可以在一定情况下对函数返回值的拷贝/移动操作进行优化。

ISO C++11标准§8.5/16中作了如下规定(省略了上下文):

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

在§12.8/31中有:

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

所以,这只是编译器优化而已。楼主可以试试用Visual Studio的Release模式进行编译,应该会跟g++一样跳过拷贝构造函数的。

这篇关于关于C++拷贝构造函数的疑惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆