33

我正在从 Java 迁移到 C++,并且对该语言的灵活性有点困惑。有一点是存储对象的三种方法:指针、引用和标量(如果我理解正确,存储对象本身)。

我倾向于尽可能使用引用,因为它尽可能接近 Java。在某些情况下,例如派生属性的 getter,这是不可能的:

MyType &MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

这不会编译,因为t只存在于范围内getSomeAttribute(),如果我返回对它的引用,它在客户端可以使用它之前将无处可指。

因此,我有两个选择:

  1. 返回一个指针
  2. 返回一个标量

返回指针如下所示:

MyType *MyClass::getSomeAttribute() {
    MyType *t = new MyType;
    return t;
}

这是可行的,但是客户端必须检查这个指针NULL才能真正确定,这对于引用来说是不必要的。另一个问题是调用者必须确保它t被释放,如果我可以避免它,我宁愿不处理它。

另一种方法是返回对象本身(标量):

MyType MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

这很简单,这正是我在这种情况下想要的:感觉就像一个参考,它不能为空。如果对象超出客户端代码的范围,则将其删除。很方便。但是,我很少看到有人这样做,这是有原因的吗?如果我返回标量而不是指针或引用,是否存在某种性能问题?

处理这个问题的最常见/最优雅的方法是什么?

4

5 回答 5

24

按值返回。编译器可以优化掉副本,所以最终结果就是你想要的。创建一个对象,并返回给调用者。

我认为您很少看到人们这样做的原因是因为您正在查看错误的 C++ 代码。;) 大多数来自 Java 的人都对做这样的事情感到不舒服,所以他们到处打电话new。然后他们到处都是内存泄漏,必须检查 NULL 和所有其他可能导致的问题。:)

值得指出的是,C++ 引用与 Java 引用几乎没有共同之处。Java 中的引用更类似于指针(它可以重新安装或设置为 NULL)。实际上,唯一真正的区别是指针也可以指向垃圾值(如果它未初始化,或者它指向超出范围的对象),并且您可以对指针进行指针运算大批。C++ 引用是对象的别名。Java 引用的行为并非如此。

于 2010-08-07T18:11:07.707 回答
3

很简单,new尽可能避免使用指针和动态分配。改为使用值、引用和自动分配的对象。当然你不能总是避免动态分配,但它应该是最后的手段,而不是第一个。

于 2010-08-07T18:12:47.607 回答
2

按值返回可能会带来性能损失,因为这意味着需要复制对象。如果它是一个大对象,比如一个列表,那么该操作可能会非常昂贵。

但是现代编译器非常擅长使这种情况不会发生。C++ 标准明确规定允许编译器在某些情况下省略副本。与您提供的示例代码相关的特定实例称为“返回值优化”。

::std::auto_ptr就个人而言,当我返回一个成员变量时,我通过(通常是 const)引用返回,并在我需要动态分配某些东西时(经常)返回某种智能指针对象。否则我按价值返回。

我也经常有const引用参数,这在 C++ 中很常见。这是一种传递参数并说“函数不允许触摸这个”的方式。基本上是一个只读参数。它应该只用于比单个整数或指针更复杂的对象。

我认为 Java 的一大变化是它const很重要并且使用非常频繁。学会理解它,让它成为你的朋友。

我还认为 Neil 的回答是正确的,即尽可能避免动态分配是一个好主意。您不应该为了实现这一点而过度扭曲您的设计,但您绝对应该更喜欢不必发生这种情况的设计选择。

于 2010-08-07T18:20:20.803 回答
0

关于按值或引用传递的一点:
考虑优化,假设一个函数是inline,如果它的参数被声明为“const DataType objectName”,DataType 可以是任何甚至基元,将不涉及对象副本;如果它的参数被声明为“const DataType & objectName”或“DataType & objectName”,那么 DataType 甚至可以是任何原语,则不会涉及地址获取或指针。在前两种情况下,输入参数都直接在汇编代码中使用。

关于引用的一点:
引用并不总是指针,例如当您在函数体中有以下代码时,引用不是指针:

int adad=5;
int & reference=adad;  

关于按值返回的一点:
正如有人提到的,使用具有优化能力的好的编译器,任何类型的按值返回都不会导致额外的副本。

关于按引用返回的一点:
对于内联函数和优化,按引用返回不会涉及地址获取或指针。

于 2010-08-07T20:10:56.077 回答
0

按值返回是 C++ 中的常见做法。然而,当你传递一个对象时,你是通过引用传递的。

例子

 main()
   {

       equity trader;

       isTraderAllowed(trader);

       ....
    }

    bool isTraderAllowed(const equity& trdobj)
    {
             ... // Perform your function routine here.
    }

上面是一个通过引用传递对象的简单示例。实际上,您将有一个名为 isTraderAllowed 的方法用于类Equity,但我向您展示了通过引用传递的实际用途。

于 2010-08-07T18:19:41.887 回答