expert
expert

Reputation: 30095

Is there performance benefit in using temporary object?

I'm reviewing HTTP Server 3 example on Boost's website. There is following code in connection class:

boost::tribool result;
boost::tie(result, boost::tuples::ignore) = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred);

where parse declared as

template <typename InputIterator>
boost::tuple<boost::tribool, InputIterator> parse(request& req, InputIterator begin, InputIterator end)

I believe the goal was to copy returned value of tribool to local variable. But what is the point of doing it via temporary object (boost::tie) if one could write something like

boost::tuple<boost::tribool, char*> result = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred);
// Our tribool is available via result.get<0>();

?

Upvotes: 1

Views: 306

Answers (4)

Luc Touraille
Luc Touraille

Reputation: 82041

The benefit is not performance, it is practicality and readability: since you are not interested by the second object returned by parse, there is no need for keeping it. It is better to ignore it entirely and only get the result you are effectively interested in, namely the tribool. The following code, which uses result, will be much clearer.

In fact, when a function returns multiple data, it is often useful (in terms of readability) to "split" it to get the individual elements separately. For instance, consider std::set<T>::insert, which returns an iterator to the element as well as a boolean indicating whether it was newly inserted. Which of the following code do you find clearer:

std::set<int> s;
std::pair<std::set<int>::iterator, bool> res = s.insert(42);

if (res.second)
{
    doSomething(res.first);
}

vs

std::set<int> s;
std::set<int>::iterator itInsertedElement;
bool isNewlyInserted;

tie(itInsertedElement, isNewlyInserted) = s.insert(42);

if (isNewlyInserted)
{
    doSomething(itInsertedElement);
}

In my opinion, the latter is easier to read.

Upvotes: 10

Pawel Zubrycki
Pawel Zubrycki

Reputation: 2713

I think they use tie mainly for convenience. If you don't need InputIterator, just the tribool value, why would you want to create named variable?

This:

boost::tribool result;
boost::tie(result, boost::tuples::ignore) = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred);

becomes this:

boost::tuple<boost::tribool, char*> results = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred);
boost::tribool result = boost::get<0>(results); // or you can use boost::get<0>(results) everywhere you use it.

And you have on stack totally useless results.

Temporary value returned from boost:tie will be probably optimized by a compiler, so there shouldn't be any memory overhead.

Upvotes: 3

Matthieu M.
Matthieu M.

Reputation: 299770

It's only a semantic consideration I think.

  1. The second element of the result is explicitly ignored, much more obvious that a trailing .get<0>()
  2. The result variable is only bound with the useful part, and no other variable is required.

Performances here should not be affected as the compiler will treat it as:

 boost::tuple<boost::tribool, char*> __tmp = request_parser_.parse(/**/);

 boost::trilbool result;
 boost::tie(result, boost::tuples::ignore) = __tmp;

and the optimizer will then take care of eliminating the cruft and reducing that as much as possible.

Upvotes: 3

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

I doubt there's any measurable performance difference (certainly not compared to the IO cost) but it's more convenient to simply refer to result rather than using get<0>() to get it out of the tuple.

Upvotes: 0

Related Questions