以这种方式返回对新创建的对象的引用,这是一种安全的做法

Is returning a reference to the newly created object this way, a safe practice?

本文关键字:一种 安全 引用 对象 返回 新创建 创建 方式      更新时间:2023-10-16

我说的是公共成员函数invertinvert_version2,它们将分数对象作为参数,并返回一个新的分数对象,该对象是参数对象的逆对象。

class fraction {
     public:
         fraction(long l1, long l2) {
             num = l1;
             den = l2;
         }
         const fraction& inverse (const fraction& f) {
              return fraction(f.den,f.num);
         }
         const fraction& inverse_version2 (const fraction& f) {
              return new fraction(f.den,f.num); 
         }
     private:
          long num;
          long den;
};

这是100%安全的做法吗?这就是我的想法,如果我错了,请纠正:函数inverse在堆栈上创建一个新的分数对象,即使返回了引用,一旦程序执行控制(有更好的术语吗?)退出该函数,内存中保存新创建的分数对象数据成员的值就会丢失,并被垃圾值取代(或者它们不是??)。

然而,函数inverse_version2动态地创建分数对象,因此是101%安全的。

请澄清在前一种情况下(在堆栈上创建的分数对象)是否确实丢失了值。

这两个版本都是错误的。在第一种情况下,您将UB作为对本地对象的返回引用,而在第二种情况下它甚至不会编译。如果您试图修复第二个函数的幼稚方式,如取消引用指针,您将得到内存泄漏。因此,100%安全的变体是:

     fraction inverse (const fraction& f) {
          return fraction(f.den,f.num);
     }

PS如果你想返回一个指向动态分配对象的指针,请返回一个智能指针:

     std::unique_ptr<fraction> inverse_ptr( const fraction& f) {
          return std::make_unique<fraction>(f.den,f.num);
     }
  1. 你正在返回一个临时的引用,你被吐司了:

    const fraction& inverse (const fraction& f) {
        return fraction(f.den,f.num);
    }
    
  2. 您是否返回一个指向动态分配对象的指针或引用?决定并更正代码
    不管怎样,两者都不是一个好主意。

    const fraction& inverse_version2 (const fraction& f) {
        return new fraction(f.den,f.num); 
    }
    

相反,您应该做的只是按值返回(并依靠RVO/NRVO来消除副本/移动),或者消除任何复制的机会
或者,如果对象真的那么大,通过std::unique_ptr

fraction inverse_v1(const fraction& f) { // Uses RVO / NRVO to eliminate temporaries
    return fraction(f.den, f.num);
}
fraction inverse_v2(const fraction& f) { // no temporaries at all
    return {f.den, f.num};
}
std::unique_ptr<fraction> inverse_v3(const fraction& f) { // smart-pointer
    return {new fraction(f.den, f.num)};
}