Базовая инициализация вектора размером
Простейший способ инициализировать вектор конкретным размером на C++ — использовать конструктор, которым принимается параметр размера:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec(5); // Создается вектор из пяти целых чисел
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
Этим кодом создается вектор из пяти целых чисел, причем все они инициализированы значением 0
. Выводится: 0 0 0 0 0
.
Инициализация конкретным значением
Чтобы инициализировать все элементы конкретным значением, используется конструктор с двумя параметрами:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec(5, 10); // Создается вектор из пяти целых чисел, Создается вектор из пяти целых чисел, всем им задается значение «10»
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
Выводится: 10 10 10 10 10
.
resize() для изменения размера вектора
Размер имеющегося вектора изменяется функцией resize()
:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec;
vec.resize(5); // Изменяется размер вектора, в нем становится пять элементов
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
vec.resize(8, 100); // Размер увеличивается до восьми, новые элементы инициализируются значением «100»
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
Выводится:
0 0 0 0 0
0 0 0 0 0 100 100 100
Инициализация диапазоном значений
С помощью функции iota
библиотеки <numeric> вектор инициализируется диапазоном значений:
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 1); // Заполняется значениями «1, 2, 3, 4, 5»
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
Выводится: 1 2 3 4 5
.
Инициализация вектора векторов
Для многомерных векторов выполняется вложенная инициализация:
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
for (const auto& row : matrix) {
for (int num : row) {
std::cout << num << " ";
}
std::cout << std::endl;
}
return 0;
}
При этом создается матрица 3 х 4, инициализированная нулями.
std::fill для инициализации вектора
Функцией std::fill
всем элементам вектора задается конкретное значение:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec(5);
std::fill(vec.begin(), vec.end(), 7);
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
Выводится: 7 7 7 7 7
.
Реальный сценарий: обработка изображений
Вот практический пример инициализации векторов размером в контексте обработки изображений:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
class Image {
private:
std::vector<std::vector<int>> pixels;
int width;
int height;
public:
Image(int w, int h) : width(w), height(h) {
pixels.resize(height, std::vector<int>(width, 0));
}
void addNoise(int intensity) {
std::srand(std::time(nullptr));
for (auto& row : pixels) {
for (int& pixel : row) {
pixel += std::rand() % intensity;
if (pixel > 255) pixel = 255;
}
}
}
void applyBlur() {
std::vector<std::vector<int>> blurred(height, std::vector<int>(width, 0));
for (int y = 1; y < height - 1; ++y) {
for (int x = 1; x < width - 1; ++x) {
int sum = 0;
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
sum += pixels[y + dy][x + dx];
}
}
blurred[y][x] = sum / 9;
}
}
pixels = std::move(blurred);
}
void print() {
for (const auto& row : pixels) {
for (int pixel : row) {
std::cout << pixel << " ";
}
std::cout << std::endl;
}
}
};
int main() {
Image img(5, 5);
std::cout << "Original Image:" << std::endl;
img.print();
img.addNoise(50);
std::cout << "\nImage with Noise:" << std::endl;
img.print();
img.applyBlur();
std::cout << "\nBlurred Image:" << std::endl;
img.print();
return 0;
}
Здесь демонстрируется инициализация векторов размером в таких задачах обработки изображений, как добавление шума и применение фильтров размытия.
Производительность
При работе с большими векторами способ инициализации сказывается на производительности. Сравним эти способы:
#include <iostream>
#include <vector>
#include <chrono>
const int SIZE = 10000000;
void benchmarkInitialization(const std::string& method, void (*initFunc)()) {
auto start = std::chrono::high_resolution_clock::now();
initFunc();
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << method << " took " << diff.count() << " seconds" << std::endl;
}
void initWithSize() {
std::vector<int> vec(SIZE);
}
void initWithResize() {
std::vector<int> vec;
vec.resize(SIZE);
}
void initWithReserveAndPushBack() {
std::vector<int> vec;
vec.reserve(SIZE);
for (int i = 0; i < SIZE; ++i) {
vec.push_back(0);
}
}
int main() {
benchmarkInitialization("Initialize with size", initWithSize);
benchmarkInitialization("Initialize with resize", initWithResize);
benchmarkInitialization("Initialize with reserve and push_back", initWithReserveAndPushBack);
return 0;
}
В этом тесте сравнивается инициализация вектора заданным размером с использованием resize()
, reserve()
и push_back()
. Запустите тест у себя в системе и сравните, какой способ эффективнее.
Инициализация векторов пользовательских типов
При работе с пользовательскими типами необходимо убедиться, что они корректно инициализированы:
#include <iostream>
#include <vector>
#include <string>
class Person {
public:
std::string name;
int age;
Person() : name("Unknown"), age(0) {}
Person(const std::string& n, int a) : name(n), age(a) {}
};
int main() {
std::vector<Person> people(3); // Создаются три «Persons» со значениями по умолчанию
for (const auto& person : people) {
std::cout << person.name << ": " << person.age << std::endl;
}
std::vector<Person> team(2, Person("John Doe", 30)); // Два «Persons» с конкретными значениями
for (const auto& person : team) {
std::cout << person.name << ": " << person.age << std::endl;
}
return 0;
}
В этом примере показана инициализация векторов пользовательских типов значениями как по умолчанию, так и конкретными.
Типичные ошибки и как их избежать
- Путаница между
size()
иcapacity()
. Не забывайте, что в первом возвращается количество элементов, а во втором — выделенное пространство. Для изменения количества элементов используйтеresize()
, для выделения пространства —reserve()
. - Лишние перераспределения. Во избежание их, зная конечный размер вектора, инициализируйте его этим размером или используйте
reserve()
. - Отсутствие инициализации элементов. При увеличении размера вектора новые элементы инициализируются значением, а в случае с неклассовыми типами — нулем.
- Неэффективная вставка. Избегайте
push_back()
в цикле, если известен конечный размер. Инициализируйте вектор корректным размером и задавайте значения оператором индексирования[]
. - Игнорирование возвращаемого значения
push_back
. Вставленный элемент не возвращается с помощьюpush_back()
. Чтобы изменить элемент после вставки, используйтеback()
или оператор индексирования.
Заключение
В C++ векторы инициализируются размером по-разному, в зависимости от конкретных сценариев.
Понимание этих способов — от простой инициализации размером до методов посложнее вроде пользовательских типов и многомерных структур — важно для эффективного программирования на C++.
Выбирая способ инициализации, учитывайте конкретные требования своих задач. Работаете вы с известным, фиксированным размером? Нужно ли в целях производительности заранее выделять память? Имеются ли пользовательские типы, которым требуется особая инициализация?
Ответив на эти вопросы, вы выберете оптимальный способ.
Читайте также:
- Удаление последнего символа строки на C++: методы и их применение
- Обучение программированию лучше начать с языка С. И вот почему
- Шаблон проектирования прототипов в современном C++
Читайте нас в Telegram, VK и Дзен
Перевод статьи ryan: C++ Initialize Vector with Size: How to Guide