Lenny White
Lenny White

Reputation: 452

C array of objects that allow for dynamic allocation

If I have a class with dynamic allocaton like std::vector. How much sense does it make to create an array with elements of that object?

I tested the following:

std::vector<int> array[2];

array[0].push_back(10);
array[0].push_back(20);
array[0].push_back(30);


array[1].push_back(40);
array[1].push_back(50);
array[1].push_back(60);

for (auto x : array[0]) {
    std::cout << x << std::endl;
}

for (auto x : array[1]) {
    std::cout << x << std::endl;
}

Which outputs the values correctly. However is this actually undefined behavior? Array elements are located contiguously in memory. When a std::vector object is initialized without specifying size, it doesn't allocate any memory. So when we create an array with two elements, is any memory allocated at all? When we then add new elements to std::vector are we writing outside of the array bounds?

Upvotes: 1

Views: 84

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 310990

An object of the type std::vector<int> has a fixed size that depends on its implementation.

Consider the following demonstrative program.

#include <iostream>
#include <vector>

int main() 
{
    std::vector<int> array[2];

    std::cout << "sizeof( std::vector<int> ) = " 
              << sizeof( std::vector<int> )
              << '\n';
                  
    std::cout << "sizeof( array = " 
              << sizeof( array )
              << '\n';
                      
    std::cout << '\n';
    
    array[0].push_back(10);
    array[0].push_back(20);
    array[0].push_back(30);


    array[1].push_back(40);
    array[1].push_back(50);
    array[1].push_back(60);
    
    std::cout << "sizeof( std::vector<int> ) = " 
              << sizeof( std::vector<int> )
              << '\n';
                  
    std::cout << "sizeof( array = " 
              << sizeof( array )
              << '\n';
                      
}   

Its output might look like

sizeof( std::vector<int> ) = 24
sizeof( array = 48

sizeof( std::vector<int> ) = 24
sizeof( array = 48

When you are adding new elements to the vectors their sizes are not changed and correspondingly the array size also is not changed.

The program is well-formed.

The class template std::vector contains as its data member a pointer to a memory where it places its elements. If there is no enough memory the vector reallocates it. But the size of an object itself of the vector type does not depend on the reallocated memory.

Upvotes: 1

paddy
paddy

Reputation: 63471

There is no undefined behavior here.

How much sense does it make to create an array with elements of that object?

This is entirely up to you, and your design considerations. It's perfectly fine to have an array of vectors.

So when we create an array with two elements, is any memory allocated at all?

Yes, memory for the array is allocated.

When we then add new elements to std::vector are we writing outside of the array bounds?

std::vector allocates memory dynamically. A default-constructed vector may or may not allocate memory. This is implementation-dependent. Internally, the vector is probably just holding pointers.

Some implementations may be smarter than this, by switching from a fixed number of elements with no dynamic allocation to using dynamic allocation if the requirements exceed that. std::string implementations commonly do this, by repurposing the internal pointer storage to hold string data instead.

Note that if you are pushing some number of elements onto a new vector, it's good practice to call reserve on that vector to avoid unnecessary reallocations as it grows.

Upvotes: 4

Related Questions