C++在使用构造函数以值方式返回类对象时出现的问题

描述

Problem test01()
{
    Problem p1;
    cout << "p1的地址:" << &p1 << endl;
    return p1;
}

void test02()
{
    Problem p2 = test01();  //这里相当于隐式转换
    cout << "p2的地址:" << &p2 << endl;

}

结果
在这里插入图片描述


从构造函数的角度出发,显然存在问题,这里只用了一次构造函数,而且p1和p2的地址是一样的。

这是由于编译器的优化导致形成的,主要是返回值优化和复制省略造成的。

具体

在非优化的情况下:
在test01的返回值不是p1本身,而是通过拷贝构造函数生成的一个新的值,可以理解为生成了一个临时匿名类对象p’,p’的再传递给新的类对象p2,这个传递相当于一个隐式转换法(这里的转换也使用了一次拷贝函数),如下例子因此p1和p2的地址不会相等。此过程中应当使用两次构造函数,两次次拷贝函数。

    Person p4 = 10; // Person p4 = Person(10);
    cout << &p4 << endl;
    Person p5 = p4; // Person p5 = Person(p4);
    cout << &p5 << endl;
    
    /* p5这里使用的是拷贝构造,这里发生拷贝,但是地址不会被拷贝,所以这里地址不同 */

编译器优化的情况下:
在C++11及以后中采用了一种新的编译优化技术(复制省略和返回值优化),因为函数返回类对象会通过拷贝构造函数生产临时类对象,这样会导致效率低下,在编译器优化后,会省略拷贝环节。

解决

不建议直接返回类对象,尽量不使用该方法去传递。

若真要解决,可以关闭编译器的优化。

在使用GNU/g++ 编译器时可以使用"-fno-elide-constructors"选项来强制g++总是调用copy构造函数,即使在用临时对象初始化另一个同类型对象的时候。

官方解释:

-fno-elide-constructors
The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases. This option also causes G++ to call trivial member functions which otherwise would be expanded inline.
In C++17, the compiler is required to omit these temporaries, but this option still affects trivial member functions.
using namespace std;


完整代码:

class  Problem
{
public:


    Problem()
    {
        cout << "构造函数的调用" << endl;
    }

    Problem(int a)
    {
        age = a;
        cout << "有参构造函数的调用" << endl;
    }

    Problem(const Problem &p)
    {
        age = p.age;
        cout << "拷贝构造函数的调用" << endl;

    }

    ~Problem()
    {
        cout << "析构函数的调用" << endl;
    }

    int age;
};

Problem test01()
{
    Problem p1;

    cout << "p1的地址:" << &p1 << endl;
    return p1;
}

void test02()
{
    Problem p3();
    Problem p2 = test01();
    cout << "p2的地址:" << &p3 << endl;

}


/*
     * @Description:    main
     * @param - l:      无
     * @return:         无
     */
int main()
{

    system("chcp 65001 > nul");
    Problem p3;
    test02();

//    system("pause");

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ORI2333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值