问题
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:
- Return a pointer
- 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?
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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.
回答5:
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.
来源:https://stackoverflow.com/questions/3431484/when-to-return-a-pointer-scalar-and-reference-in-c