C++指针作为函数的返回值(附带实例)
我们可以把 C++ 中的指针当作一种基本数据类型,它除了可以定义变量和作为函数参数外,还可以将它作为函数的返回值。
与函数参数的传递类似,函数的返回过程同样涉及返回数据的拷贝,当我们需要从函数内返回较大体积的数据或者返回的数据不能被拷贝时,就可以采用返回指向这个数据的指针来代替返回数据本身。
例如,在单例模式的 getInstance() 函数中,由于需要返回的对象不能在返回过程中被复制,因此使用指针作为返回值,从函数内返回指向该对象的指针来代替返回该对象本身:
例如,如果前面的 getInstance() 函数的代码修改如下,虽然该函数能够通过编译,但在运行时可能会导致严重的错误:
消灭这个错误最好的方法就是牢记下面的规则,对于以指针为返回值的函数:
与函数参数的传递类似,函数的返回过程同样涉及返回数据的拷贝,当我们需要从函数内返回较大体积的数据或者返回的数据不能被拷贝时,就可以采用返回指向这个数据的指针来代替返回数据本身。
例如,在单例模式的 getInstance() 函数中,由于需要返回的对象不能在返回过程中被复制,因此使用指针作为返回值,从函数内返回指向该对象的指针来代替返回该对象本身:
// 以 SalarySys*指针作为返回值 static SalarySys* getInstance() { if ( nullptr == m_pInstance ) m_pInstance = new SalarySys(); return m_pInstance; // 返回指向 SalarySys 对象的指针 }需要特别注意的是,不能把一个指向函数内局部变量的指针作为返回值。这是因为函数内部定义的局部变量在函数结束后,其生命周期就结束了,它所占用的内存会被自动释放,此时该内存地址变成无效。如果仍将指向这个地址的指针作为函数返回值返回给主调函数,并在主调函数中访问该指针所指向的数据,将产生不可预料的结果。
例如,如果前面的 getInstance() 函数的代码修改如下,虽然该函数能够通过编译,但在运行时可能会导致严重的错误:
#include <iostream> using namespace std; // 错误的 getInstance() 函数 static SalarySys* getInstance() { if ( nullptr == m_pInstance ) { // 定义一个局部变量 sys SalarySys sys; m_pInstance = &sys; // 获得局部变量的指针 } return m_pInstance; // 返回指向局部变量 sys 对象的指针 } int main() { // ... // 获得的指针指向 getInstance() 函数内的局部变量 sys SalarySys* p = SalarySys::getInstance(); // getInstance() 函数执行完毕后 // 局部变量 sys 已经被销毁,对它的访问是无效且无意义的 p->Input(); //... }在主函数中,我们通过 getInstance() 函数获得的指针指向的是函数内部的一个局部对象 sys。当 getInstance() 函数调用结束后,这个对象会被自动销毁。如果这时仍然通过这个指针试图访问这个已被销毁的对象,其结果是不可预料的,有可能正确,也有可能错误。而这恰恰使得这个错误具有极大的隐蔽性,时而正确、时而错误,很难被发现。
消灭这个错误最好的方法就是牢记下面的规则,对于以指针为返回值的函数:
- 可以返回用 new 全新申请的内存地址;
- 可以返回全局变量的地址;
- 可以返回静态变量的地址;
- 不可以返回局部变量的地址。