2015-01-03 2 views
7

В можно использовать списки инициализаторов для инициализации параметров в функциях. В чем его цель? Не может ли быть сделано то же самое с константными векторами? В чем разница между двумя программами ниже?список инициализаторов против вектора

Использование списка инициализатора:

#include <iostream> 

using namespace std; 

int sumL(initializer_list<int> l){ 
    int sum = 0; 
    for (const auto i: l){ 
     sum += i; 
    } 
    return sum; 
} 

int main(){ 

    cout << sumL({1, 2, 3}) << "\n"; 

    return 0; 
} 

Используя константный вектор:

#include <iostream> 
#include <vector> 

using namespace std; 

int sumV(const vector<int> l){ 
    int sum = 0; 
    for (const auto i: l){ 
     sum += i; 
    } 
    return sum; 
} 

int main(){ 

    cout << sumV({1, 2, 3}) << "\n"; 

    return 0; 
} 
+2

Второй код требует больше, чем необходимо (и вектор построен также с помощью initializer_list) –

+0

Offtopic: обратите внимание, что вы делаете копию вектора, т. Е. Вы не использовали ссылку &. То же самое имеет место в цикле for, теперь это просто int, но с более крупными объектами ссылка избежит того, что вы копируете каждый объект в вектор. – Michiel

ответ

6

Совместное использование std::initializer_list как аргумент конструкторов контейнера (и аналогичные) классов, что позволяет удобно инициализацию этих контейнеров из нескольких объектов того же типа. Конечно, вы можете использовать std::initializer_list иначе, а затем использовать тот же синтаксис {}.

Поскольку размер std::initializer_list имеет фиксированный размер, он не требует динамического распределения и, следовательно, может быть эффективно реализован. A std::vector, с другой стороны, требует динамического распределения памяти. Даже в вашем простом примере маловероятно, что компилятор будет оптимизировать эти накладные расходы (избегайте посредника std::vector и его динамическое распределение памяти). Помимо этого, нет никакой разницы в результатах ваших программ (хотя вы должны принять аргумент const std::vector<int>&, чтобы избежать копирования и связанного с ним распределения динамической памяти).

3

Семантика двух совершенно разных. initializer_list имеет семантику указателя, тогда как vector имеет семантику значений.

В первом примере, компилятор генерирует код, подобный следующему:

int const __temp_array[3] = {1, 2, 3}; 
cout << sumL(std::initializer_list<int>(__temp_array, __temp_array + 3)) << "\n"; 

Это объясняется в [dcl.init.list]/5. Как вы можете видеть, в пределах sumL у вас есть доступ к указателям const элементам braced-init-list, это означает, что у вас нет другого выбора, кроме как скопировать элементы из списка.

В случае sumV вы могли бы std::moved элементов из vector, если это необходимо (при условии, типа параметра не const).

Аналогично, копирование initializer_list выполняет мелкие копии, то есть будут копироваться только указатели, при этом копирование vector, конечно же, означает, что элементы будут скопированы.

В вашем примере ни один из вышеперечисленных пунктов не имеет никакого значения, кроме построения vector потребуется динамическое выделение памяти, а при построении initializer_list - нет.

3

initializer_list использует оптимальное место хранения и предотвращает ненужные вызовы, он рассчитан на легкий вес, а с vector - распределение кучи, и может быть больше копий/движений.

1

initalizer_list не является обобщенным контейнером, как std :: vector. Основной целью является инициализация объекта. Если низкий уровень подслушивания и распределение кучи привлекательны для вас, я бы предложил посмотреть на std :: array. Это массив с фиксированным размером стека, который имеет все удобства контейнера STL, который по существу представляет собой тонкую оболочку поверх c-массива.

Смежные вопросы