在 C++ 中何时返回指针、标量和引用?

发布于 2024-11-04 02:43:46 字数 895 浏览 2 评论 0原文

我正从 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;
}

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

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

I'm moving from Java to C++ and am a bit confused of the language's flexibility. One point is that there are three ways to store objects: A pointer, a reference and a scalar (storing the object itself if I understand it correctly).

I tend to use references where possible, because that is as close to Java as possible. In some cases, e.g. getters for derived attributes, this is not possible:

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

This does not compile, because t exists only within the scope of getSomeAttribute() and if I return a reference to it, it would point nowhere before the client can use it.

Therefore I'm left with two options:

  1. Return a pointer
  2. Return a scalar

Returning a pointer would look like this:

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

This'd work, but the client would have to check this pointer for NULL in order to be really sure, something that's not necessary with references. Another problem is that the caller would have to make sure that t is deallocated, I'd rather not deal with that if I can avoid it.

The alternative would be to return the object itself (scalar):

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

That's pretty straightforward and just what I want in this case: It feels like a reference and it can't be null. If the object is out of scope in the client's code, it is deleted. Pretty handy. However, I rarely see anyone doing that, is there a reason for that? Is there some kind of performance problem if I return a scalar instead of a pointer or reference?

What is the most common/elegant approach to handle this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

淡写薰衣草的香 2024-11-11 02:43:46

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

我认为你很少看到人们这样做的原因是因为你看到了错误的 C++ 代码。 ;)
大多数来自 Java 的人都觉得做这样的事情不舒服,所以他们到处调用 new 。然后他们到处都会出现内存泄漏,必须检查 NULL 以及可能导致的所有其他问题。 :)

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

Return by value. The compiler can optimize away the copy, so the end result is what you want. An object is created, and returned to the caller.

I think the reason why you rarely see people do this is because you're looking at the wrong C++ code. ;)
Most people coming from Java feel uncomfortable doing something like this, so they call new all over the place. And then they get memory leaks all over the place, have to check for NULL and all the other problems that can cause. :)

It might also be worth pointing out that C++ references have very little in common with Java references.
A reference in Java is much more similar to a pointer (it can be reseated, or set to NULL).
In fact the only real differences are that a pointer can point to a garbage value as well (if it is uninitialized, or it points to an object that has gone out of scope), and that you can do pointer arithmetics on a pointer into an array.
A C++ references is an alias for an object. A Java reference doesn't behave like that.

迷荒 2024-11-11 02:43:46

很简单,尽可能避免使用指针和 new 动态分配。请改用值、引用和自动分配的对象。当然,您不能总是避免动态分配,但这应该是最后的手段,而不是首选。

Quite simply, avoid using pointers and dynamic allocation by new wherever possible. Use values, references and automatically allocated objects instead. Of course you can't always avoid dynamic allocation, but it should be a last resort, not a first.

东风软 2024-11-11 02:43:46

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

但现代编译器非常善于避免这种情况发生。 C++ 标准明确规定允许编译器在某些情况下删除副本。与您提供的示例代码相关的特定实例称为“返回值优化”。

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

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

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

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

Returning by value can introduce performance penalties because this means the object needs to be copied. If it is a large object, like a list, that operation might be very expensive.

But modern compilers are very good about making this not happen. The C++ standards explicitly states that the compiler is allowed to elide copies in certain circumstances. The particular instance that would be relevant in the example code you gave is called the 'return value optimization'.

Personally, I return by (usually const) reference when I'm returning a member variable, and return some sort of smart pointer object of some kind (frequently ::std::auto_ptr) when I need to dynamically allocate something. Otherwise I return by value.

I also very frequently have const reference parameters, and this is very common in C++. This is a way of passing a parameter and saying "the function is not allowed to touch this". Basically a read-only parameter. It should only be used for objects that are more complex than a single integer or pointer though.

I think one big change from Java is that const is important and used very frequently. Learn to understand it and make it your friend.

I also think Neil's answer is correct in stating that avoiding dynamic allocation whenever possible is a good idea. You should not contort your design too much to make that happen, but you should definitely prefer design choices in which it doesn't have to happen.

南街九尾狐 2024-11-11 02:43:46

按值返回是 C++ 中常见的做法。但是,当您传递对象时,您是通过引用传递的。

示例

 main()
   {

       equity trader;

       isTraderAllowed(trader);

       ....
    }

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

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

Returning by value is a common thing practised in C++. However, when you are passing an object, you pass by reference.

Example

 main()
   {

       equity trader;

       isTraderAllowed(trader);

       ....
    }

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

The above is a simple example of passing an object by reference. In reality, you would have a method called isTraderAllowed for the class equity, but I was showing you a real use of passing by reference.

娇妻 2024-11-11 02:43:46

关于通过值或引用传递的一点:
考虑到优化,假设一个函数是内联的,如果它的参数声明为“const DataType objectName”,DataType可以是任何东西,甚至是基元,则不会涉及对象复制;并且如果其参数被声明为“const DataType & objectName”或“DataType & objectName”,那么数据类型也可以是任何东西,甚至是基元,则不会涉及地址获取或指针。在前面的两种情况下,输入参数都直接在汇编代码中使用。

关于参考的一点:
引用并不总是指针,例如,当函数体内有以下代码时,引用就不是指针:

int adad=5;
int & reference=adad;  

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

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

A point regarding passing by value or reference:
Considering optimizations, assuming a function is inline, if its parameter is declared as "const DataType objectName" that DataType could be anything even primitives, no object copy will be involved; and if its parameter is declared as "const DataType & objectName" or "DataType & objectName" that again DataType could be anything even primitives, no address taking or pointer will be involved. In both previous cases input arguments are used directly in assembly code.

A point regarding references:
A reference is not always a pointer, as instance when you have following code in the body of a function, the reference is not a pointer:

int adad=5;
int & reference=adad;  

A point regarding returning by value:
as some people have mentioned, using good compilers with capability of optimizations, returning by value of any type will not cause an extra copy.

A point regarding return by reference:
In case of inline functions and optimizations, returning by reference will not involve address taking or pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文