Coming Soon

This lesson is currently being developed

Introduction to std::vector and list constructors

Master dynamic arrays with the vector container.

Dynamic arrays: std::vector
Chapter
Beginner
Difficulty
45min
Estimated Time

What to Expect

Comprehensive explanations with practical examples

Interactive coding exercises to practice concepts

Knowledge quiz to test your understanding

Step-by-step guidance for beginners

Development Status

In Progress

Content is being carefully crafted to provide the best learning experience

Preview

Early Preview Content

This content is still being developed and may change before publication.

16.2 — Introduction to std::vector and list constructors

In this lesson, you'll learn how to create and initialize std::vector objects using various constructors. You'll discover the flexibility that std::vector provides over C-style arrays and understand the different ways to set up vectors for your programs.

What is std::vector?

std::vector is a sequence container that represents a dynamic array. Unlike C-style arrays, std::vector can change its size during runtime, automatically managing memory allocation and deallocation.

Think of std::vector like a smart, resizable container:

  • It starts empty or with initial values you specify
  • It can grow to accommodate new elements
  • It can shrink when elements are removed
  • It always knows its current size
  • It provides safe access to elements

Including std::vector

To use std::vector, you must include the <vector> header:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> numbers; // Now you can use std::vector
    return 0;
}

Basic std::vector syntax

The basic syntax for declaring a std::vector is:

std::vector<element_type> vector_name;

For example:

std::vector<int> integers;        // Vector of integers
std::vector<double> decimals;     // Vector of double-precision numbers
std::vector<char> characters;     // Vector of characters
std::vector<bool> flags;          // Vector of boolean values

std::vector constructors

std::vector provides several constructors to create vectors in different ways. Let's explore each one:

1. Default constructor (empty vector)

Creates an empty vector with no elements:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> numbers; // Empty vector
    
    std::cout << "Size: " << numbers.size() << std::endl;
    std::cout << "Empty: " << (numbers.empty() ? "Yes" : "No") << std::endl;
    
    return 0;
}

Output:

Size: 0
Empty: Yes

2. Fill constructor (size with default value)

Creates a vector with a specified number of elements, each initialized to the default value:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> numbers(5); // 5 integers, each initialized to 0
    
    std::cout << "Size: " << numbers.size() << std::endl;
    std::cout << "Elements: ";
    for (int i = 0; i < numbers.size(); ++i)
    {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

Size: 5
Elements: 0 0 0 0 0 

3. Fill constructor (size with specific value)

Creates a vector with a specified number of elements, each initialized to a specific value:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> scores(7, 100); // 7 integers, each initialized to 100
    std::vector<double> prices(3, 9.99); // 3 doubles, each initialized to 9.99
    
    std::cout << "Scores (" << scores.size() << " elements): ";
    for (int score : scores)
    {
        std::cout << score << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Prices (" << prices.size() << " elements): ";
    for (double price : prices)
    {
        std::cout << "$" << price << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

Scores (7 elements): 100 100 100 100 100 100 100 
Prices (3 elements): $9.99 $9.99 $9.99 

4. Initializer list constructor

Creates a vector from a list of values (C++11 and later):

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> primes = {2, 3, 5, 7, 11, 13};
    std::vector<std::string> colors = {"red", "green", "blue"};
    std::vector<double> temperatures = {23.5, 25.0, 22.8, 24.1};
    
    std::cout << "Primes: ";
    for (int prime : primes)
    {
        std::cout << prime << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Colors: ";
    for (const std::string& color : colors)
    {
        std::cout << color << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

Primes: 2 3 5 7 11 13 
Colors: red green blue 

5. Copy constructor

Creates a vector as a copy of another vector:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> original = {1, 4, 9, 16, 25};
    std::vector<int> copy(original); // Copy constructor
    
    std::cout << "Original: ";
    for (int value : original)
    {
        std::cout << value << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Copy: ";
    for (int value : copy)
    {
        std::cout << value << " ";
    }
    std::cout << std::endl;
    
    // Modify the copy to show they're independent
    copy[0] = 999;
    
    std::cout << "After modifying copy:" << std::endl;
    std::cout << "Original[0]: " << original[0] << std::endl;
    std::cout << "Copy[0]: " << copy[0] << std::endl;
    
    return 0;
}

Output:

Original: 1 4 9 16 25 
Copy: 1 4 9 16 25 
After modifying copy:
Original[0]: 1
Copy[0]: 999

6. Range constructor

Creates a vector from a range of elements (from another container):

#include <vector>
#include <iostream>
#include <array>

int main()
{
    std::array<int, 5> arr = {10, 20, 30, 40, 50};
    std::vector<int> vec(arr.begin(), arr.end()); // Range constructor
    
    std::cout << "Array: ";
    for (int value : arr)
    {
        std::cout << value << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Vector from array: ";
    for (int value : vec)
    {
        std::cout << value << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

Array: 10 20 30 40 50 
Vector from array: 10 20 30 40 50 

Comparing constructors

Here's a comprehensive example showing different construction methods:

#include <vector>
#include <iostream>

int main()
{
    // Different ways to create vectors
    std::vector<int> empty;                    // Empty vector
    std::vector<int> sized(4);                 // 4 zeros: [0, 0, 0, 0]
    std::vector<int> filled(3, 42);            // 3 copies of 42: [42, 42, 42]
    std::vector<int> listed = {1, 2, 3, 4, 5}; // From initializer list
    std::vector<int> copied(listed);           // Copy of 'listed'
    
    std::cout << "Empty size: " << empty.size() << std::endl;
    std::cout << "Sized: ";
    for (int val : sized) std::cout << val << " ";
    std::cout << std::endl;
    
    std::cout << "Filled: ";
    for (int val : filled) std::cout << val << " ";
    std::cout << std::endl;
    
    std::cout << "Listed: ";
    for (int val : listed) std::cout << val << " ";
    std::cout << std::endl;
    
    std::cout << "Copied: ";
    for (int val : copied) std::cout << val << " ";
    std::cout << std::endl;
    
    return 0;
}

Output:

Empty size: 0
Sized: 0 0 0 0 
Filled: 42 42 42 
Listed: 1 2 3 4 5 
Copied: 1 2 3 4 5 

List initialization vs direct initialization

There's an important distinction between list initialization and direct initialization:

#include <vector>
#include <iostream>

int main()
{
    // These create different vectors!
    std::vector<int> v1(3, 5);  // Direct init: 3 elements, each with value 5
    std::vector<int> v2{3, 5};  // List init: 2 elements with values 3 and 5
    
    std::cout << "v1 (direct): ";
    for (int val : v1) std::cout << val << " ";
    std::cout << "(size: " << v1.size() << ")" << std::endl;
    
    std::cout << "v2 (list): ";
    for (int val : v2) std::cout << val << " ";
    std::cout << "(size: " << v2.size() << ")" << std::endl;
    
    return 0;
}

Output:

v1 (direct): 5 5 5 (size: 3)
v2 (list): 3 5 (size: 2)

Working with different element types

std::vector works with any type:

#include <vector>
#include <iostream>
#include <string>

int main()
{
    // Vector of strings
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
    
    // Vector of characters
    std::vector<char> vowels = {'a', 'e', 'i', 'o', 'u'};
    
    // Vector of booleans
    std::vector<bool> answers = {true, false, true, true};
    
    // Vector of doubles
    std::vector<double> measurements(5, 0.0); // 5 zeros
    
    std::cout << "Names: ";
    for (const std::string& name : names)
    {
        std::cout << name << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Vowels: ";
    for (char vowel : vowels)
    {
        std::cout << vowel << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Answers: ";
    for (bool answer : answers)
    {
        std::cout << (answer ? "Yes" : "No") << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

Names: Alice Bob Charlie 
Vowels: a e i o u 
Answers: Yes No Yes Yes 

Memory and performance considerations

Capacity vs size

std::vector maintains two important properties:

  • Size: The number of elements currently stored
  • Capacity: The number of elements that can be stored without allocating new memory
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> numbers = {1, 2, 3};
    
    std::cout << "Size: " << numbers.size() << std::endl;
    std::cout << "Capacity: " << numbers.capacity() << std::endl;
    
    // Add more elements
    numbers.push_back(4);
    numbers.push_back(5);
    numbers.push_back(6);
    
    std::cout << "After adding elements:" << std::endl;
    std::cout << "Size: " << numbers.size() << std::endl;
    std::cout << "Capacity: " << numbers.capacity() << std::endl;
    
    return 0;
}

Output:

Size: 3
Capacity: 3
After adding elements:
Size: 6
Capacity: 6

Constructor performance

Different constructors have different performance characteristics:

// Fast - no memory allocation needed
std::vector<int> empty;

// Fast - single memory allocation, elements default-initialized
std::vector<int> sized(1000);

// Fast - single memory allocation, elements copy-initialized
std::vector<int> filled(1000, 42);

// Fast - single memory allocation for known size
std::vector<int> listed = {1, 2, 3, 4, 5};

// Moderate - copy existing memory
std::vector<int> copied(other_vector);

Best practices for std::vector construction

1. Use initializer lists when you know the values

// Good - clear and concise
std::vector<std::string> weekdays = {"Mon", "Tue", "Wed", "Thu", "Fri"};

// Less clear
std::vector<std::string> weekdays;
weekdays.push_back("Mon");
weekdays.push_back("Tue");
// ... etc

2. Pre-size when you know the final size

// Good - avoids multiple reallocations
std::vector<int> numbers;
numbers.reserve(1000); // Pre-allocate space
// ... fill with data

// Or use fill constructor if all elements are the same
std::vector<int> zeros(1000, 0);

3. Be careful with parentheses vs braces

std::vector<int> v1(10, 5);  // 10 elements, each value 5
std::vector<int> v2{10, 5};  // 2 elements: 10 and 5

4. Use const when the vector won't change

const std::vector<std::string> colors = {"red", "green", "blue"};
// colors cannot be modified

Common mistakes to avoid

1. Forgetting to include <vector>

// Error - missing include
// std::vector<int> numbers; // Won't compile

#include <vector>
std::vector<int> numbers; // OK

2. Confusing constructor syntax

std::vector<int> wrong(5, 10, 15); // Error - too many arguments
std::vector<int> correct(5, 10);   // OK - 5 elements, each value 10

3. Assuming capacity equals size

std::vector<int> vec(5);
std::cout << vec.capacity(); // Might be 5, but could be larger

Summary

std::vector provides multiple constructors to create vectors in different ways:

  • Default constructor: Creates an empty vector
  • Fill constructor: Creates a vector with specified size and values
  • Initializer list constructor: Creates a vector from a list of values
  • Copy constructor: Creates a copy of another vector
  • Range constructor: Creates a vector from a range of elements

Choose the appropriate constructor based on your needs:

  • Use initializer lists when you know the exact values
  • Use fill constructors when you need many copies of the same value
  • Use the default constructor when you'll add elements later
  • Use copy constructor when you need an independent copy

In the next lesson, you'll learn about the challenges of working with std::vector's size type and indexing.

Quiz

  1. What header file must you include to use std::vector?
  2. What's the difference between std::vector<int> v(3, 5) and std::vector<int> v{3, 5}?
  3. How do you create a vector with 10 elements, each initialized to zero?
  4. What's the difference between a vector's size and capacity?
  5. Which constructor would you use to create a copy of an existing vector?

Practice exercises

Try these exercises to practice std::vector constructors:

  1. Constructor comparison: Create vectors using each type of constructor and display their contents and sizes. Create vectors of integers, strings, and doubles.

  2. Student grades: Create a vector to store test scores using the fill constructor (assume all students got 85). Then create another vector with specific scores using an initializer list. Display both vectors.

  3. Data migration: Create a C-style array with some values, then create a std::vector using the range constructor to copy those values. Compare accessing elements from both.

  4. Performance test: Create large vectors using different constructors and measure their creation time (you can use a simple timer or just observe). Try vectors with 100,000 elements using fill constructor vs adding elements one by one.

Continue Learning

Explore other available lessons while this one is being prepared.

View Course

Explore More Courses

Discover other available courses while this lesson is being prepared.

Browse Courses

Lesson Discussion

Share your thoughts and questions

💬

No comments yet. Be the first to share your thoughts!

Sign in to join the discussion