Пара векторных конструкторов: список инициализаторов против явной конструкции - PullRequest
0 голосов
/ 01 ноября 2018

Я вызываю конструктор std::pair<vector<int>, int> двумя способами:

  • переход в список инициализаторов
  • передача в явном векторе (r-значение).

По какой-то причине версия списка инициализатора делает копию (и уничтожает ее).
Вот мой минимальный пример кода:

auto dummy() {
    return pair<vector<int>, int>{ {1,2,3,4,5}, 1};
}

auto dummy1() {
    return pair<vector<int>, int>{ vector{1,2,3,4,5}, 1};
}

auto dummy2() {
    return optional<vector<int> > { {1,2,3,4,5} };
}

После проверки проводника компилятора я обнаружил, что список инициализаторов dummy() version вызывает operator new дважды и delete один раз. Это не происходит ни с явной версией конструкции dummy1(), ни с аналогичным конструктором std::optional в dummy2(). Я не ожидал бы такого поведения. Кто-нибудь знает почему? Я также проверил clang.

1 Ответ

0 голосов
/ 02 ноября 2018

Проблема связана с std::pair конструкторами и разрешением вывода / перегрузки аргументов шаблона:

pair( const T1& x, const T2& y ); // (1)

template< class U1, class U2 >
pair( U1&& x, U2&& y );           // (2)

Обратите внимание, что есть, по крайней мере, один «отсутствующий» конструктор:

pair( T1&& x, T2&& y );           // (3)

Когда вы используете инициализацию списка для первого параметра, выбранный конструктор будет не (2)U1 = std::initializer_list<int>), а (1) 1 . Таким образом, вам нужно создать временную std::vector<int>, которая передается как const -ссылка на (1), которая должна сделать копию.

Эмпирически это можно подтвердить одним из следующих способов:

  • создание собственного pair с третьим конструктором, упомянутым выше & mdash; в этом случае будет выбран (3), а временный vector будет перемещен;
  • явно создает std::initializer_list<int> при создании std::pair:
pair<vector<int>, int>{ std::initializer_list<int>{1,2,3,4,5}, 1 };

С другой стороны std::optional как конструктор с одним шаблоном:

template < class U = value_type >
constexpr optional( U&& value );

... но есть значение по умолчанию для U, что делает этот конструктор допустимым кандидатом для разрешения перегрузки.


1 Когда вы звоните pair{ {1,2,3,4,5}, 1 }, U1 находится в невыбранном контексте в пределах (2) [temp.deduct.type] # 5.6 , поэтому вычет не выполняется, поэтому выбран (1).

...