C++中拷贝构造函数的调用及返回值优化问题

1、C++中返回值优化问题

返回值优化(Return Value Optimization,简称RVO),是这么一种优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消 耗一个构造函数(Constructor)的调用、一个复制构造函数的调用(Copy Constructor)以及一个析构函数(Destructor)的调用的代价。而如果稍微做一点优化,就可以将成本降低到一个构造函数的代价。
详细说明:C++中临时对象及返回值优化


2、拷贝构造函数的调用

原文链接:拷贝构造函数的调用以及浅拷贝与深拷贝的理解

首先,关闭返回值优化:
在这里插入图片描述

然后,执行以下函数:

#include <iostream>
#include <string.h>

class student {
public:
    // 普通构造函数
    student(int i, char* c, int a, float s) {
        std::cout << "Constructing..." << std::endl;
        id = i;
        age = a;
        score = s;
        name = new char[strlen(c) + 1]; //申请堆空间
        if (name != 0) strcpy(name, c);
    }
    
    // 显示声明拷贝函数,自定义实现深拷贝
    student(const student& s) {
        std::cout << "Copy Constructing..." << std::endl;
        id = s.id; //一般成员简单复制
        age = s.age;
        score = s.score;
        name = new char[strlen(s.name) + 1]; //先申请堆空间
        if (name != 0) strcpy(name, s.name); //复制字符串
    };
    
    ~student() {
        std::cout <<"Destructing..."<< std::endl;
        delete []name;
    }
    
    int getid() {
        return id;
    }
    
    char* getName() {
        return name;
    }
    
private:
    int id;
    char* name;
    int age;
    float score;
};

// 函数返回值是类对象,函数执行完成返回调用时,系统会自动调用拷贝构造函数
student g() {
    student s1(10, (char*)"Lina", 18, 86);
    return s1;
}

// 如果函数的形参是类的对象,调用函数时,用实参的值初始化形参时,系统会自动调用拷贝构造函数
void print_1(student s) {
    std::cout << "学号:" << s.getid() << std::endl;
}

int main() {
    student s1(10, (char*)"Wang", 18, 86); //创建和初始化对象
    std::cout << std::endl;
    // 第一种情况,用s1初始化s2。第一次调用拷贝构造函数
    student s2 = s1;
    std::cout << std::endl;
    // 第二种情况,对象s2作为print_1的实参。第二次调用拷贝构造函数
    print_1(s2);
    std::cout << std::endl;
    
    // 第三种情况,函数的返回值是类对象,函数返回时调用拷贝构造函数
    //s2 = g();
    student s3 = g();//s3是要先分配,所以执行的是拷贝构造,不是赋值
    std::cout << s3.getName() <<std::endl;
    //禁止返回值优化以后,g()return的时候调用了显式的拷贝构造函数,构造了Ts,“=”采用了浅拷贝,拷贝完,Ts释放。
    //所以程序结束后再释放 s2报错。
    //注意::所有存在堆空间的类,必须用深拷贝!!任何地方不允许出现钱拷贝。
    std::cout << "happy" <<std::endl;
    return 0;
    //getchar();
}

当输入为:

student s3 = g();
std::cout << s3.getName() <<std::endl;

“=” 用来初始化,执行的是显式拷贝构造函数,也就是深拷贝。

   输出:
   Constructing... //s1调用构造函数
   
   Copy Constructing... //用s1初始化s2。第一次调用拷贝构造函数
   
   Copy Constructing... //对象s2作为print_1的实参。第二次调用拷贝构造函数
   学号:10
   Destructing...//析构临时变量
   
   Constructing... //函数里的临时对象s1调用构造函数
   Copy Constructing... //函数的返回值是类对象,函数返回时调用拷贝构造函数
   Destructing...//函数里的临时对象s1析构
   Copy Constructing...//返回值临时对象初始化s3,调用拷贝构造函数
   Destructing...//返回值临时对象析构
   Lina
   happy
   Destructing...//s1 析构
   Destructing...//s2 析构
   Destructing...//s3 析构
   Program ended with exit code: 0

当输入为:

s2 = g();
std::cout << s2.getName() <<std::endl;

“ = ” 用来赋值,执行的是浅拷贝。也就是返回值的指针和s2的指针指向同一块内存区域。所以当返回值对象被析构以后,再执行s2的析构,释放的空间已经不存在!

   输出:
   Constructing... //s1调用构造函数
   
   Copy Constructing... //用s1初始化s2。第一次调用拷贝构造函数
   
   Copy Constructing... //对象s2作为print_1的实参。第二次调用拷贝构造函数
   学号:10
   Destructing...//析构临时变量
   
   Constructing... //函数里的临时对象s1调用构造函数
   Copy Constructing... //函数的返回值是类对象,函数返回时调用拷贝构造函数
   Destructing... //函数里的临时对象s1析构
   Destructing...//返回值临时对象析构
   Lina
   happy
   Destructing...//s1 析构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值