MST

星途 面试题库

面试题:C++函数返回常量引用与性能优化

在一个复杂的C++项目中,存在一个频繁调用的函数,其返回值为一个自定义类对象。从性能优化角度考虑,何时选择返回常量引用,何时选择返回值传递?请详细分析其中的优缺点,并给出相应的代码示例。
48.6万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

返回常量引用

  • 适用场景:当函数返回的对象是一个已经存在的、不会被函数修改的临时对象,并且该对象的生命周期在函数结束后依然有效时,适合返回常量引用。例如,函数返回类内部的成员变量(前提是该成员变量不会在函数结束后被销毁)。
  • 优点
    • 性能高:避免了对象的拷贝构造,直接返回对象的引用,对于大型对象或拷贝构造开销大的对象,性能提升明显。
    • 避免临时对象创建:不会创建额外的临时对象用于返回值传递。
  • 缺点
    • 生命周期限制:返回的对象必须在函数结束后依然存在。如果返回局部对象的引用,会导致悬空引用,程序运行时会出现未定义行为。
    • 不能修改返回值:由于是常量引用,调用者不能修改返回的对象。
  • 代码示例
class MyClass {
public:
    MyClass() = default;
    MyClass(const MyClass&) { std::cout << "Copy constructor called" << std::endl; }
    ~MyClass() = default;
private:
    int data = 0;
    friend const MyClass& getInstance();
};

const MyClass& getInstance() {
    static MyClass instance;
    return instance;
}

返回值传递

  • 适用场景:当函数返回的对象是一个全新创建的对象,且函数结束后该对象不再需要保留其在函数内的状态,调用者需要拥有该对象的独立副本时,适合返回值传递。例如,函数内部创建了一个局部对象并返回。
  • 优点
    • 灵活性高:调用者得到的是一个独立的对象副本,可以自由修改。
    • 不存在生命周期问题:不用担心返回的对象在函数结束后被销毁,因为调用者得到的是新创建的副本。
  • 缺点
    • 性能开销:会调用拷贝构造函数(C++11 引入了移动语义后,在某些情况下可以优化为移动构造),对于大型对象或拷贝构造开销大的对象,性能会受到影响。
    • 创建临时对象:需要创建临时对象用于返回值传递。
  • 代码示例
class MyClass {
public:
    MyClass() = default;
    MyClass(const MyClass&) { std::cout << "Copy constructor called" << std::endl; }
    ~MyClass() = default;
private:
    int data = 0;
};

MyClass createObject() {
    MyClass obj;
    return obj;
}