问题
In the following function, I want to take a vector objects
and return a copy of one of the elements of that vector. Since the code below compiles correctly, I'm assuming that the iterator copy_objects.back()
is automatically dereferenced. But I don't know for certain. What is happening in the return statement?
MyObject best(vector<MyObject>& objects) {
vector<MyObject> copy_objects = objects;
sort(copy_objects.begin(), copy_objects.end(), compare_MyObject_func);
return copy_objects.back();
}
I know there are other ways to accomplish the simple task at hand, but I'm curious to know what's going on in this example.
Follow-up question...
Using the definition of the best
function above, I get the following compile error:
error: invalid initialization of non-const reference of type ‘std::vector<MyObject>&’ from an rvalue of type ‘std::vector<MyObject>’
bestObject = best(myfunction(objects));
^
Where the relevant type declarations are:
MyObject bestObject;
vector<MyObject> objects;
vector<MyObject> myfunction(vector<MyObject>&);
My intuition tells me this error is related to the original question above. But, I don't understand what the problem is.
回答1:
"Dereference" usually refers to applying the unary *
operator to a pointer or other iterator (like *p
). This terminology is confusing because it doesn't have anything to do with reference types in C++, so the standards committee are moving to use "perform indirection" instead.
Anyway, copy_objects.back()
does not return an iterator at all. It returns a reference to the object (an actual reference type). You can see this because the return type for std::vector<T>::back
is const_reference
which is a typedef for const value_type&
, where value_type
is T
. You don't ever "dereference" references. If you want to copy from a reference, you just need to treat it like a normal object.
int x = 0;
int& y = x;
int z = y;
In this example, z
will be a copy of the object referred to by both x
and y
.
In addition to this, I recommend just taking the argument by value too (remove the &
):
MyObject best(vector<MyObject> objects) {
sort(objects.begin(), objects.end(), compare_MyObject_func);
return objects.back();
}
You're going to copy it anyway, so taking it by reference is pointless. Especially a non-const
reference suggests that you're going to modify the given argument, which you don't. In fact, a reference parameter gives you worse performance when the vector
could be moved into the function. The reference type parameter will never move.
Answer to your extended question:
myfunction
returns by value, which means that the object it returns is a temporary object (it's a copy of whatever was inside it). You can't bind a non-const
reference (the parameter of best
) to a temporary object. This makes sense because then the temporary object would disappear (because it's temporary) and the reference would be left referring to nothing.
If you made the parameter type a const
reference, it would be fine, because const
references extend the lifetime of a temporary object. If you made the parameter a non-reference, it would also be fine, because it would make a local copy of the temporary object.
回答2:
back()
does not return an iterator. Instead, it returns a reference to the last element of the vector.
回答3:
You are performing a shallow copy of objects and then sorting the copy. back()
returns a reference to the last element, so you are making a copy from that reference into the return variable in the caller's scope.
回答4:
You are passing in a reference - hence you can return a reference:
MyObject& best(vector<MyObject>& objects) {
vector<MyObject>::iterator result = objects.begin();
if(result == objects.end()) throw std::runtime_error("Empty");
else {
for(vector<MyObject>::iterator pos = std::next(result);
pos != objects.end();
++pos)
{
// Might be ! compare_MyObject_func
if(compare_MyObject_func(*result, *pos)) result = pos;
}
}
return *result;
}
There is not need to sort anything if you are interested in a certain element, only.
Note: the complexity for a lookup of a certain element is O(n), while sorting is O(n log(n))
来源:https://stackoverflow.com/questions/20937611/c-returning-reference-from-function-with-type-of-dereferenced-type