对于它们的使用,我将分以下多种情况进行分析。如果不知道通用引用,可以先去了解一下。
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值的复制而已。