Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observing weird behavior with 'auto' and std::minmax

I am using GCC 4.7.2 and Boost 1.58.0 on SUSE Enterprise Linux 11. I have the following code snippet which basically goes through a list of polygons to compute their length/width. I'm seeing strange output when using the 'auto' keyword with the std::minmax function. To compare, I also declare a second variable where the types are explicitly declared (i.e., dim vs dim1).

namespace gtl = boost::polygon;
typedef gtl::polygon_90_data<int> LayoutPolygon;
typedef gtl::rectangle_data<int> LayoutRectangle;
static LayoutFeatureVec
calc_stats(LayoutPolygonSet const& lp)
{
   LayoutFeatureVec v;
   LayoutFeature f;
   LayoutRectangle y;
   for (LayoutPolygon const& p : lp) {
      // Compute bounds.
      gtl::extents(y, p);

      // Get width/length (shorter/longer).
      // FIXME: Why does this not work with auto??
      cout << gtl::delta(y, gtl::HORIZONTAL) << " " << gtl::delta(y, gtl::VERTICAL) << endl;

      auto dim = std::minmax(gtl::delta(y, gtl::HORIZONTAL),
                             gtl::delta(y, gtl::VERTICAL));

      std::pair<int, int> dim1 = std::minmax(gtl::delta(y, gtl::HORIZONTAL),
                                             gtl::delta(y, gtl::VERTICAL));

      cout << dim.first << " " << dim.second << endl;
      cout << dim1.first << " " << dim1.second << endl;

      <snip>
      v.push_back(f);
   }

   return v;
}

For the first iteration of this loop, the expected output is this which is correct.

380 420
380 420
380 420

However, if I comment out 'dim1' and rerun the same code (i.e., just have auto dim), I get weird results with std::minmax.

380 420
140737295994126 140737295994126

What am I doing wrong here?

Here is the minimal example (edited based on answer below).

#include <iostream>
#include <algorithm>
#include <boost/polygon/polygon.hpp>

using namespace std;

namespace gtl = boost::polygon;
using namespace gtl::operators;

int main(int argc, char** argv)
{
    gtl::rectangle_data<int> x(0,0,5,5);

    auto dim = std::minmax(gtl::delta(x, gtl::HORIZONTAL), gtl::delta(x, gtl::VERTICAL));
    cout << dim.first << " " << dim.second << endl;

    return 0;
}
like image 280
user4979733 Avatar asked Apr 11 '16 17:04

user4979733


1 Answers

This is one of those cases of where not to use auto as the type specifier. std::minmax returns a pair of references:

template< class T > 
std::pair<const T&,const T&> minmax( const T& a, const T& b );

That's what auto will deduce. But delta() returns a temporary. So when you write:

auto dim = std::minmax(gtl::delta(y, gtl::HORIZONTAL),
                       gtl::delta(y, gtl::VERTICAL));

dim is holding two dangling references. But when you write:

std::pair<int, int> dim1 = std::minmax(...);

You're just holding the values directly. That's why this works but auto doesn't. The extra conversion you're performing prevents you from holding dangling references.


Alternatively, and for completeness, you could use a different overload of minmax that doesn't return references:

template< class T >
std::pair<T,T> minmax( std::initializer_list<T> ilist);

which just involves some extra braces:

auto dim2 = std::minmax({gtl::delta(y, gtl::HORIZONTAL),
                         gtl::delta(y, gtl::VERTICAL)});

But I'd suggest just explicitly naming the type. That seems less error-prone to me.

like image 122
Barry Avatar answered Nov 07 '22 15:11

Barry