Подтвердить что ты не робот

Наблюдая странное поведение с помощью "auto" и std:: minmax

Я использую GCC 4.7.2 и Boost 1.58.0 на SUSE Enterprise Linux 11. У меня есть следующий фрагмент кода, который в основном проходит через список полигонов, чтобы вычислить их длину/ширину. Я вижу странный вывод при использовании ключевого слова "auto" с помощью функции std:: minmax. Для сравнения я также объявляю вторую переменную, где типы явно объявлены (т.е. 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;
}

Для первой итерации этого цикла ожидаемый результат является правильным.

380 420
380 420
380 420

Однако, если я прокомментирую "dim1" и повторю один и тот же код (т.е. просто отключился автоматически), я получаю странные результаты с помощью std:: minmax.

380 420
140737295994126 140737295994126

Что я здесь делаю неправильно?

Вот минимальный пример (отредактированный на основе ответа ниже).

#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;
}
4b9b3361

Ответ 1

Это один из тех случаев, когда не использовать auto в качестве спецификатора типа. std::minmax возвращает пару ссылок:

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

Вот что auto выведет. Но delta() возвращает временный. Итак, когда вы пишете:

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

dim держит две свисающие ссылки. Но когда ты пишешь:

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

Вы просто держите значения напрямую. Вот почему это работает, а auto нет. Дополнительное преобразование, которое вы выполняете, не дает вам удерживать висячие ссылки.


В качестве альтернативы и для полноты вы можете использовать другую перегрузку minmax, которая не возвращает ссылки:

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

что включает в себя некоторые дополнительные скобки:

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

Но я бы предложил просто явно назвать тип. Это кажется менее подверженным ошибкам для меня.