Should I clear() containers passed in as a parameter, or swap in a new object? [closed]
-
31-05-2021 - |
Frage
I'm in a discussion at work as to how to properly handle containers as parameters.
We have a function that takes in a container parameter, and wants to return the container filled ONLY with what the function puts into it:
class bar;
void foo(std::vector<bar> &bars)
{
//do stuff that fills bars.
//exceptions may be thrown.
//we may also legally return early
return;
}
On one side of the discussion, we have people that say we should bars.clear()
first and then run the function.
For example:
void foo(std::vector<bar> &bars)
{
bars.clear();
//do stuff that fills bars.
//exceptions may be thrown.
//we may also legally return early
return;
}
My own preference is to try to reach the strong exception guarantee as closely as I can, which means making a local container, filling that and swapping before returning, but otherwise leaving bars
untouched.
For example:
void foo(std::vector<bar> &bars)
{
std::vector<bar> localBars;
//do stuff that fills localBars.
//exceptions may be thrown.
//we may also legally return early
if (returnEarly)
{
bars.swap(localBars);
return;
}
//do more stuff that may change localBars
bars.swap(localBars);
return;
}
The first example is the 'classic' method; of clearing your parameters before doing anything and going from there.
The second method, to me, sets up a strong exception guarantee (assuming nothing else the function does can change internal states), and avoids a clear() call.
Are there any advantages or disadvantages to picking one method over the other one?
Note that for this function, a strong exception guarantee isn't required; if the function fails nothing in the parameters or anything else it does will matter by the time it gets up to the exception handler.
Lösung
The two are really different.
Advantages of clear
:
- reuse memory
- no out-dated information left in
bars
Advantages of swap
:
- strong exception guarantee
The question cannot be answered in general, what semantics/guarantees do you seek in your case ?
Andere Tipps
You've mentionned one advantage of using swap: it provides a strong exception guarantee. Whether this is really important is another question: if the argument passed by the client will be immediately destructed when the exception propagates (almost always the case in the code I've seen), it really doesn't matter.
There is another important difference: clear()
doesn't free memory or
reduce the capacity. If the client code calls your function in a loop,
with the vector defined outside of the loop, the vector will quickly
attain its maximum size, and you will not have any reallocations when
filling it. With the swap strategy, of course, you always reallocate.
And if you're not concerned with this sort of performance issue, you
should be returning the vector, not taking a non-const reference to it
as a parameter.
swap() is better with respect to exceptions. clear may have an advantage if the container is huge and you have memory constraints. a more functional/cleaner style can be:
std::vector<bar> void foo()
{
std::vector<bar> bars;
...
return bars;
}
RVO will take care of it most of the time and with c++11 and move constructors/assignment it will just be efficient.