In C++, Is It Still Bad Practice to Return a Vector from a Function

In C++, is it still bad practice to return a vector from a function?

Dave Abrahams has a pretty comprehensive analysis of the speed of passing/returning values.

Short answer, if you need to return a value then return a value. Don't use output references because the compiler does it anyway. Of course there are caveats, so you should read that article.

Why is it OK to return a 'vector' from a function?

Can we guarantee it will not die?

As long there is no reference returned, it's perfectly fine to do so. words will be moved to the variable receiving the result.

The local variable will go out of scope. after it was moved (or copied).

Efficient way to return a std::vector in c++

In C++11, this is the preferred way:

std::vector<X> f();

That is, return by value.

With C++11, std::vector has move-semantics, which means the local vector declared in your function will be moved on return and in some cases even the move can be elided by the compiler.

Is it a bad idea to return an object by value that contains a member vector?

Your writing gf255_poly dst = poly1; followed by return dst; is exploiting Named Returned Value Optimisation (NRVO).

This is a more recent innovation than Returned Value Optimisation but is certainly implemented by modern compilers, irrespective of the C++ standard they are targeting. To be absolutely clear, NRVO is not a C++11 specific thing.

Exploiting NRVO is not a bad design choice as using it makes source code easier to read and maintain.

Best practice to return a vector for nested loop in C++11

However it seems to me that the second approach (doStuff2) is better in my case, since it supports vector reuse. Any suggestions?

The second option (doStuff2) is better than the first, because it avoids reallocating the vector. That said, you should (probably) consider using a visitor pattern:

Your code (if I understood you correctly):

// "function will be called from a nested loop, requesting the vector
// (and processing it's elements) million times, so unnecessary
// (re)allocations should be avoided."
void yourCientCode()
{
std::vector<TVec*> vec;
for(auto x: ???) for(auto y: ???) // nested loop (a million(?) times)
{
A::doStuff2(x, y, vec);
performClientComputation(vec);
}
}

Alternative code:

// "function will be called from a nested loop, requesting the vector
// (and processing it's elements) million times, so unnecessary
// (re)allocations should be avoided."
void yourCientCode()
{
for(auto x: ???) for(auto y: ???) // nested loop
{
A::doStuff3(x, y, performClientComputation); // computation function should
// be injected as a visitor
}
}

This way, no vector is returned. Client code doesn't have to "get vector then apply computation", but "apply computation on elements satisfying whatever conditions" (see Demeter's Law).

Having a vector (or not) becomes an internal implementation detail (as far as client code is concerned) and can be optimized later, without altering client code at all).

return a std::vector in c++

In std::vector size is a member function, not a member variable. You use it like this:

int size = a.size();

If you don't have the parentheses, it is a syntax error.

Incidentally, another thing you can do to simplify your code is declare vectors like this:

std::vector<int> a;

Or in C++11

std::vector<int> a{};

Both of these will default-construct the vector -- this works for any class type.

Doing it this way,

std::vector<int> a = std::vector<int>();

is not as good because it is longer and makes you type things twice, and also it copy initializes it rather than default constructing it, which is slightly different and may be less efficient.

Is the practice of returning a C++ reference variable evil?

In general, returning a reference is perfectly normal and happens all the time.

If you mean:

int& getInt() {
int i;
return i; // DON'T DO THIS.
}

That is all sorts of evil. The stack-allocated i will go away and you are referring to nothing. This is also evil:

int& getInt() {
int* i = new int;
return *i; // DON'T DO THIS.
}

Because now the client has to eventually do the strange:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt; // must delete...totally weird and evil

int oops = getInt();
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

Note that rvalue references are still just references, so all the evil applications remain the same.

If you want to allocate something that lives beyond the scope of the function, use a smart pointer (or in general, a container):

std::unique_ptr<int> getInt() {
return std::make_unique<int>(0);
}

And now the client stores a smart pointer:

std::unique_ptr<int> x = getInt();

References are also okay for accessing things where you know the lifetime is being kept open on a higher-level, e.g.:

struct immutableint {
immutableint(int i) : i_(i) {}

const int& get() const { return i_; }
private:
int i_;
};

Here we know it's okay to return a reference to i_ because whatever is calling us manages the lifetime of the class instance, so i_ will live at least that long.

And of course, there's nothing wrong with just:

int getInt() {
return 0;
}

If the lifetime should be left up to the caller, and you're just computing the value.

Summary: it's okay to return a reference if the lifetime of the object won't end after the call.

Is it bad practice to return a non const reference to an element of a private vector member?

Is it bad practice to return a vector element by reference?

Yes, in general? In most cases, I would think if you took the time to encapsulate a member variable of a class as private in order to control the access and manipulation of that variable, designing a member function that will easily break that control renders the first step moot. This may not always be true depending on the use case, but here you pose the problem so abstractly that it is hard to give a specific answer. The only real problem I can identify in your post is this:

Returning an element by value is less efficient and since it is a copy, it is less efficient.

I guess the real question to ask here is there a meaningful, measurable performance difference between maintaining greater access control to the member variable versus having more direct access to the underlying memory so you can manipulate it faster? You are right that the return by reference is more efficient in some ways, but does that actually make a practical difference in your particular code?

Additionally, it also matters what level of data integrity you need to maintain for the private member variables you are exposing. einpoklum makes a great point that many standard containers follow this paradigm. They have no expectations on the values that are stored in the container, only that they maintain control over allocation/deletion of the memory held by them. Your class may have a stronger control requirements about what values the member values take. For example, if all the data elements in that vector needed to be non-negative, then by exposing a reference to that memory you lose the ability to have the class make those kind of data integrity guarantees. It really just depends on the requirements, although I prefer the paradigm of selectively releasing control over a member variable as needed rather than giving full access and slowly taking it away when you want to add additional guarantees.



Related Topics



Leave a reply



Submit