【问题标题】:Create reference to new object创建对新对象的引用
【发布时间】:2011-06-19 07:09:20
【问题描述】:

我刚刚学习 C++,遇到了以下难题:

作为一个 C++ 新手,我读到使用引用而不是指针(如果可能)通常是一个好主意,所以我试图尽早养成这个习惯。结果,我有很多具有一般形式的方法

void myMethod(ParamClass const& param);

现在,我想知道调用这些方法的最佳方式是什么。当然,每次调用都需要一个不同的对象作为参数传递,据我所知,创建它的唯一方法是 new 运算符,所以现在我正在执行以下操作:

myObject.myMethod(*new ParamClass(...));

虽然这种方法完全有效,但我想知道是否没有另一种已经建立的“c++ 方式”可以做到这一点。

感谢您的帮助! 丹

【问题讨论】:

  • 这样做,你正在泄漏内存,因为你永远不会在任何地方保存指针值。
  • 这本书“使用 Qt 4 进行 C++ GUI 编程”有一个出色的附录,名为“Java 和 C# 程序员的 C++ 简介”。如果这就是你的背景,它可能会提供一个有效的“快速开始”来改变你在语言之间建立的一些模式。如果您不想购买这本书,大多数图书馆都可以使用 ILL 获得副本。 (不过,如果您正在考虑使用 Qt,请获取本书

标签: c++ parameter-passing reference-type


【解决方案1】:

尝试: myObject.myMethod(ParamClass(...)); 在 C++ 中,与 Java 不同,您不必总是说 new 来创建新对象。

【讨论】:

    【解决方案2】:

    既定的做法是使用自动局部变量:

    ParamClass myParam;
    myOjbect.myMethod(myParam);
    

    通过以您的方式使用new,您将产生内存泄漏。一旦函数返回,什么都不会处理该对象 - C++ 不像其他一些语言那样具有垃圾收集功能。

    【讨论】:

      【解决方案3】:

      你应该尽量不要使用new,因为使用它会带来内存管理的麻烦。

      对于您的示例,只需执行以下操作:

      int main(int, char*[])
      {
        SomeObject myObject;
      
        // two phases
        ParamClass foo(...);
        myObject.myMethod(foo);
      
        // one phase
        myObject.myMethod(ParamClass(...));
      
        return 0;
      }
      

      我推荐第一种方法(两次),因为第二种方法存在一些微妙的问题。

      编辑:cmets 并不适合描述我所指的陷阱。

      正如@Fred Nurk 所引用的,该标准对临时人员的生命周期做了一些说明:

      [class.temporary]

      (3) 临时对象被销毁作为评估完整表达式 (1.9) 的最后一步,该完整表达式 (从词法上) 包含它们的创建点。即使评估以抛出异常结束也是如此。销毁临时对象的值计算和副作用仅与完整表达式相关联,与任何特定子表达式无关。

      (5) 引用所绑定的临时对象或引用所绑定的子对象的完整对象的临时对象在引用的生命周期内持续存在 [注意:除了在某些情况下... ]

      (5) [例如...] 在函数调用 (5.2.2) 中对引用参数的临时绑定一直持续到包含该调用的完整表达式完成为止。

      这可能导致大多数编译器无法捕捉到的两个细微错误:

      Type const& bound_bug()
      {
        Type const& t = Type(); // binds Type() to t, lifetime extended to that of t
        return t;
      } // t is destroyed, we've returned a reference to an object that does not exist
      
      Type const& forwarder(Type const& t) { return t; }
      
      void full_expression_bug()
      {
        T const& screwed = forwarder(T()); // T() lifetime ends with `;`
        screwed.method(); // we are using a reference to ????
      }
      

      Argyrios 应我的要求对 Clang 进行了修补,以便它检测到第一种情况(实际上还有一些我最初没有想到的情况)。但是,如果 forwarder 的实现不是内联的,则第二个可能很难评估。

      【讨论】:

      • 你指的是什么“微妙的陷阱”?对我来说听起来像是 FUD。
      • @Alf:我希望...尝试将绑定的临时文件传递给T const& foo(T const& t) { return t; },这真的很有趣:/ 绑定临时文件对于粗心的人来说是一个雷区,当编译器超出其深度时它来诊断这个。
      • @Matthiu:就我而言,现在它是公开且明确的纯 FUD。没有“绑定临时”之类的东西。也许您的意思是临时绑定到引用,在这种情况下,它与传递变量相同(无法区分)。
      • 感谢大家的回答。
      • @AlfP.Steinbach:他含糊其辞,但我认为没有任何理由严重影响答案。这当然不错,也不错。
      【解决方案4】:

      您需要了解对象的生命周期。如果您将*new ParamClass 传递给函数,则您将新对象的所有权授予该函数。如果函数没有销毁它(并且它不应该在给出引用的情况下这样做),你会得到内存泄漏。

      相反,您应该这样做:

      ParamClass myParamClass(...);
      myObject.myMethod(myParamClass);
      

      【讨论】:

        【解决方案5】:

        当你写作时

        myObject.myMethod(*new ParamClass(...)); 
        

        你丢失了指向新对象的指针。也就是说,这将起作用,但您稍后将无法delete 对象。所以你可以这样做:

        ParamClass pc(...);
        myObject.myMethod(pc);
        

        或者,更简单

        myObject.myMethod(ParamClass(...));
        

        或者,如果出于某种莫名其妙的原因需要动态分配

        ParamClass* pPc = new ParamClass(...);
        myObject.myMethod(*pPc);
        ...
        delete pPc;
        

        或者,使用智能指针来避免手动删除。比如:

        boost::scoped_ptr<ParamClass> spPc(new ParamClass(...));
        myObject.myMethod(*pPc);
        

        希望对你有帮助

        【讨论】:

          【解决方案6】:

          请注意,将先前创建的对象(我是指用户定义类的对象)的值分配给 java 和 c++ 中的新对象之间存在很大差异 ,它是关于:

          C++中的1- : object new =(object) old [创建一个从旧到新的对象的副本,当你修改更新时,旧的不会 em> 改变!]

          2- in java : object new =(object) old [创建对旧对象的引用,当您修改较新的对象时,较旧的对象也会 改变(非常非常重要)]

          结论:

          在 java 中:“object new =(object) old”与 c++ 中的“object &new =(object) old”相同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多