关于c++值传递,引用,通用引用的使用总结

对于它们的使用,我将分以下多种情况进行分析。如果不知道通用引用,可以先去了解一下。

1.read-only,not-assignment

1.内置类型

void func(int val) {
    if(val != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(const int &val) {
    if(val != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(int &&val) {
    if(val != 0) {
        dosome();
    } else {
        dosome();
    }
}

以上三个函数,我们应该选择哪种类型的参数呢?答案是第一个。

原因很简单,对于内置类型来讲,除非修改元素,否则均使用值传递即可。因为使用其他类型也不会优化你的程序内存,反而可能会不小心导致其他的问题。

2.不包含资源相关的复合类型

struct Counter {
    uint64_t count1;
    uint64_t count2;
};

void func(Counter counter) {
    if(counter.count1 != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(const Counter &counter) {
    if(counter.count1 != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(Counter &&counter) {
    if(counter.count1 != 0) {
        dosome();
    } else {
        dosome();
    }
}

以上三个函数,我们应该选择哪个类型的参数呢?答案是第二个。

原因很简单,对于复合类型来说,使用const &可以减少传递参数时的拷贝,节省内存和时间。为何不采用第三个呢,答案是传递右值仍然会导致复制的发生(结构体中只有内置类型),浪费时间和内存。

3.包含资源相关的复合类型

struct Student {
    uint64_t id;
    std::string name;
    Student()=default;
    Student(const Student &other)=default;
    Student(Student &&other):id(other.id),name(std::move(other.name)){}
};

void func(Student student) {
    if(student.id != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(const Student &student) {
    if(student.id != 0) {
        dosome();
    } else {
        dosome();
    }
}

void func(Student &&student) {
    if(student.id != 0) {
        dosome();
    } else {
        dosome();
    }
}

以上三个函数,我们应该选择哪个类型的参数呢?答案仍是第二个。

原因很简单,对于复合类型来说,使用const &可以减少传递参数时的拷贝,节省内存和时间。为何不采用第三个呢,答案是传递右值没必要,因为传递const &的花销少,而且不会影响到原类型(被移动后使用导致的core dump)。

2assignment

1.内置类型

int test = 0;

void func(int val) {
    test = val;
}

void func(const int &val) {
    test = val;
}

void func(int &&val) {
    test = val;
}

以上三个函数,我们应该选择哪种类型的参数呢?答案是第一个。

和之前一样,除非修改值,否则内置类型使用值传递即可。

2.不包含资源相关的复合类型

struct Counter {
    uint64_t count1;
    uint64_t count2;
};

Counter test;

void func(Counter counter) {
    test = counter;
}

void func(const Counter &counter) {
    test = counter;
}

void func(Counter &&counter) {
    test = counter;
}

以上三个函数,我们应该选择哪个类型的参数呢?答案是第二个。

原因很简单,对于这种复合类型来讲,使用const &只需要1次拷贝行为,而使用 &&类型,需要两次拷贝(一次构造,一次=)。

3.包含资源相关的复合类型

struct Student {
    uint64_t id;
    std::string name;
    Student()=default;
    Student(const Student &other)=default;
    Student(Student &&other):id(other.id),name(std::move(other.name)){}
    Student &operator(Student &&other) {
        id = other.id;
        name = std::move(other.name);
    }
};

Student test;

void func(Student student) {
    test = student;
}

void func(const Student &student) {
    test = student;
}

void func(Student &&student) {
    test = std::move(student);
}

以上三个函数,我们应该选择哪个类型的参数呢?答案是第三个。

原因很简单,对于有资源相关元素的复合类来讲(比如,string,vector,list,map,unique_ptr),使用移动引用可以最大幅度的减小复制带来的花销。对于以上而言,花销仅仅是两次int值的复制而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值