Возвращает станд.:: дорогостоящий список?

Я бы сделал это так:

dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));

Просто и легко. Согласно этому сообщению в блоге это даже быстрее, чем большинство циклов, поскольку его базовая реализация обращается к элементам по индексу, а не по счетчику (см. Этот ответ) .

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

19
задан Daniel Daranas 7 July 2009 в 14:08
поделиться

5 ответов

Если вы вернете std :: list by value он не просто скопирует заголовок списка, он скопирует один узел списка для каждого элемента в списке. Так что да, для большого списка это дорого.

Если список построен в функции, которая его возвращает, тогда вы сможете воспользоваться преимуществами оптимизации именованного возвращаемого значения, чтобы избежать ненужной копии. Однако это характерно для вашего компилятора. Он никогда не применяется, если, например, список уже существовал до вызова функции (например, если это переменная-член объекта).

Распространенной идиомой в C ++, чтобы избежать возврата контейнеров по значению, является использование итератора вывода. в качестве параметра. Итак, вместо:

std::list<int> getListOfInts() {
    std::list<int> l;
    for (int i = 0; i < 10; ++i) {
        l.push_back(i);
    }
    return l;
}

Вы делаете:

template<typename OutputIterator>
void getInts(OutputIterator out) {
    for (int i = 0; i < 10; ++i) {
        *(out++) = i;
    }
}

Затем вызывающий:

std::list<int> l;
getInts(std::back_inserter(l));

Часто после того, как компилятор завершает встраивание и оптимизацию, код более или менее идентичен.

Преимущество этого заключается в том, что вызывающий не привязан к определенной коллекции - например, он может добавить элементы в вектор вместо списка, если это более полезно в конкретных обстоятельствах. Если ему нужно увидеть каждый элемент только один раз, вместо их всех вместе, тогда он может сэкономить память, обрабатывая их в потоковом режиме, используя итератор вывода собственного изобретения.

Недостатки те же, что и у любого кода шаблона: реализация должна быть доступна для вызывающего по адресу время компиляции, и вы можете получить много «дублированного» объектного кода для нескольких экземпляров шаблона. Конечно, вы можете использовать тот же шаблон без использования шаблонов, взяв указатель функции (плюс указатель данных пользователя, если необходимо) в качестве параметра и вызвав его один раз с каждым элементом, или определив абстрактный класс IntVisitor с чистым виртуальным членом функция, и вызывающая сторона предоставит ее экземпляр.

Недостатки такие же, как и у любого кода шаблона: реализация должна быть доступна вызывающей стороне во время компиляции, и вы можете получить много «дублированного» объектного кода для нескольких экземпляров шаблона. Конечно, вы можете использовать тот же шаблон без использования шаблонов, взяв указатель функции (плюс указатель данных пользователя, если необходимо) в качестве параметра и вызвав его один раз с каждым элементом, или определив абстрактный класс IntVisitor с чистым виртуальным членом функция, и вызывающая сторона предоставит ее экземпляр.

Недостатки такие же, как и у любого кода шаблона: реализация должна быть доступна вызывающей стороне во время компиляции, и вы можете получить много «дублированного» объектного кода для нескольких экземпляров шаблона. Конечно, вы можете использовать тот же шаблон без использования шаблонов, взяв указатель функции (плюс указатель данных пользователя, если необходимо) в качестве параметра и вызвав его один раз с каждым элементом, или определив абстрактный класс IntVisitor с чистым виртуальным членом функция, и вызывающая сторона предоставит ее экземпляр.

[Edit: TED указывает в комментарии, что еще один способ избежать копирования без использования шаблонов - это передать вызывающим абонентом список по ссылке. Это, безусловно, работает, просто дает вызывающей стороне меньше гибкости, чем шаблон, и, следовательно, не является идиомой, используемой STL. Это хороший вариант, если вам не нужны «преимущества этого», о которых я говорил выше. Однако одно из первоначальных намерений STL - отделить «алгоритмы» (в данном случае все, что определяет значения) от «контейнеров» (в данном случае, тот факт, что значения хранятся в списке, а не в в вектор, массив или набор самосортировки, или просто распечатать без их сохранения).]

34
ответ дан 30 November 2019 в 03:20
поделиться

Это (как всегда) зависит. Конструктор копирования может быть вызван или не вызван возвратом в следующем коде.

std::list<int> foo() {
  std::list<int> bar;
  // ...
  return bar;
};

Он не может быть вызван, если компилятор применяет оптимизацию возвращаемого значения . Если вызывается конструктор копирования, то он, вероятно, дороже по сравнению с указателем для больших списков, а если он не вызывается, то быстрее вернуть прямой список (поскольку он позволяет избежать динамического распределения)

Лично я не переживаю по этому поводу и возвращаю прямой список. Тогда, только когда мой профилировщик скажет, что это проблема, я рассматриваю оптимизацию.

5
ответ дан 30 November 2019 в 03:20
поделиться

Если вы вернетесь по значению, будет вызван конструктор копирования, и элементы будут скопированы один за другим. Иногда вас спасет оптимизация именованных значений, как было указано одним из них.

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

  • Передать список по ссылке, который будет заполнен функцией. Таким образом вы сообщаете функции, куда поместить данные, и копировать не нужно, потому что вы помещаете ее в последнее место.
  • Выделите список в куче и верните его. Вы должны вернуть его в интеллектуальном указателе, таком как std :: auto_ptr или boost :: shared_ptr, чтобы гарантировать удаление и безопасность исключений.
2
ответ дан 30 November 2019 в 03:20
поделиться

Я полагаю, вызывается конструктор копирования.

0
ответ дан 30 November 2019 в 03:20
поделиться

Это может быть дорогостоящим, поскольку копирует каждый элемент в списке. Что еще более важно, у него другое поведение: вам нужна копия списка или вам нужен указатель на исходный список?

0
ответ дан 30 November 2019 в 03:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: