Skip to content

返回值、引用、指针

返回值

当返回局部变量时一定要返回值,同时较小的结构也可以用过值来进行返回。不能返回其引用或者指针。对于占用内存较大的局部变量,C++有返回值优化的技术。不必担心无效的拷贝。

使用场景:返回一些简单数据类型。如int,char,float。

返回引用

A& a(){ return *this;} 就生成了一个固定地址的指针,并把指针带给你

但A a() { return *this;}会生成一个临时对象变量,并把这个临时变量给你
这样就多了一步操作

使用场景:返回较大的全局变量或者返回对象成员,避免复制。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <vector>
using namespace std;

vector<int>& modifyVector(vector<int>& vec) {
    vec.push_back(10); // 修改vec
    return vec;        // 返回修改后的vec的引用
}

int main() {
    vector<int> myVec = {1, 2, 3};
    vector<int>& refVec = modifyVector(myVec);
    // 使用refVec
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class MyClass {
private:
    int value;

public:
    MyClass(int val) : value(val) {}

    // 返回成员变量的引用
    int& getValue() {
        return value;
    }

    // 设置成员变量的值
    void setValue(int val) {
        value = val;
    }
};

int main() {
    MyClass obj(5);

    // 获取value的引用
    int& ref = obj.getValue();

    // 直接修改对象的成员变量
    ref = 10;

    // 输出修改后的value
    std::cout << "New value: " << obj.getValue() << std::endl;  // 输出 "New value: 10"

    return 0;
}

const引用

使用引用固然能在函数返回时提高程序的性能,但是如果我们想要返回一个较大结构的临时变量呢?是不是只能返回值呢?

显然结果并不是这样的,我们可以使用const关键字对引用进行修饰从而延长被引用对象的生命周期,比如使用const Foo &foo = f()就是正确的

Only local const references prolong the lifespan

这里引用下大佬博客上总结的两点

  1. 引用必须是静态的,也就是必须用const来修饰这个引用。这是因为函数的返回值属于右值,也就是(rvalue)。普通的引用是左值引用,也就是lvalue reference。左值引用不能指向右值引用,只有const的左值引用才能用来指向右值
  2. 本来f()的返回值是一个临时的变量,在它调用结束后,就应该销毁了。可是通过像这样const Foo& foo = f();,把临时的返回值赋值给一个const左值引用,f()返回值并不会立即销毁。这等于是在const引用的作用域内,延长了f()返回值的存活时间

所谓右值就是等号右边的值,一般为函数的返回值或者是明确的数值,右值只能在等号右边,并不能作为左值并被赋值

右值引用

右值引用是C++11中新加入的内容,是一个尤为重要的概念,其主是要用来解决C++98/03中遇到的两个问题,第一个问题就是临时对象非必要的昂贵的拷贝操作,第二个问题是在模板函数中如何按照参数的实际类型进行转发。通过引入右值引用,很好的解决了这两个问题,改进了程序性能

相比于&是对左值进行绑定,&&就是对右值进行一个绑定,我们可以这样完成绑定

1
2
3
4
5
6
// 左值引用
int i = 100;
int &a = i;

// 右值引用
int &&b = 100;

右值可以看作是一种特殊的匿名变量,通过右值引用的声明,右值又“重获新生”,其生命周期与右值引用类型变量的生命周期一样长,只要该变量还活着,该右值临时量将会一直存活下去

同时右值引用可以看作是加了const的左值引用,其自身是一个左值,能够被任意修改,而其本质却是临时变量的右值,所以左值引用可以指向一个右值引用,而右值引用去不能被另外一个右值引用所指向

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int &&i = 100;

// 正确做法
i++;
int tmp = 200; i = tmp;

int &left = i;

// 错误做法
int &&j = 200;
j = i;

返回指针

使用场景:当函数需要返回动态分配的内存或者需要提供对对象的可选访问(例如,可以返回空指针以表示某种条件)时,使用指针(当需要返回指针时,最好使用智能指针)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class MyClass {
public:
    MyClass() {}
    void doSomething() {}
};

MyClass* createMyClassObject() {
    MyClass* obj = new MyClass();
    return obj;
}

int main() {
    MyClass* myObj = createMyClassObject();
    // 使用myObj
    myObj->doSomething();

    delete myObj; // 不要忘记释放内存
    return 0;
}

以上代码最好用智能指针代替。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <memory>

class MyClass {
public:
    MyClass() {}
    void doSomething() {}
};

std::unique_ptr<MyClass> createMyClassObject() {
    return std::make_unique<MyClass>();
}

int main() {
    std::unique_ptr<MyClass> myObj = createMyClassObject();
    // 使用myObj
    myObj->doSomething();

    // 当myObj离开作用域时,它所指向的对象会自动被销毁
    return 0;
}