Я бы сделал это так:
dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));
Просто и легко. Согласно этому сообщению в блоге это даже быстрее, чем большинство циклов, поскольку его базовая реализация обращается к элементам по индексу, а не по счетчику (см. Этот ответ) .
Конечно, при наличии дубликатов будет выдано исключение, поэтому вам придется проверить перед слиянием.
Если вы вернете 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 - отделить «алгоритмы» (в данном случае все, что определяет значения) от «контейнеров» (в данном случае, тот факт, что значения хранятся в списке, а не в в вектор, массив или набор самосортировки, или просто распечатать без их сохранения).]
Это (как всегда) зависит. Конструктор копирования может быть вызван или не вызван возвратом в следующем коде.
std::list<int> foo() {
std::list<int> bar;
// ...
return bar;
};
Он не может быть вызван, если компилятор применяет оптимизацию возвращаемого значения . Если вызывается конструктор копирования, то он, вероятно, дороже по сравнению с указателем для больших списков, а если он не вызывается, то быстрее вернуть прямой список (поскольку он позволяет избежать динамического распределения)
Лично я не переживаю по этому поводу и возвращаю прямой список. Тогда, только когда мой профилировщик скажет, что это проблема, я рассматриваю оптимизацию.
Если вы вернетесь по значению, будет вызван конструктор копирования, и элементы будут скопированы один за другим. Иногда вас спасет оптимизация именованных значений, как было указано одним из них.
Основные параметры, позволяющие избежать копирования, следующие:
Это может быть дорогостоящим, поскольку копирует каждый элемент в списке. Что еще более важно, у него другое поведение: вам нужна копия списка или вам нужен указатель на исходный список?