program size when using a std::vector

Program file bigger when using vector. My 2d grid contains 448 numbers,
so 1,792 bytes but the program grows by 60 k when using a vector.

gcc builds this exec : aa 365,152 bytes 2018-12-24 13:35 aa
------
gcc builds this exec : aa 298,464 bytes 2018-12-24 13:29 aa
------

My question is : Is this correct ? The difference in program size seems like a
lot.
TIA
1
2
const std::vector<std::vector<int>> myvectorgc /* 7 x 64 ints */
const std::array<std::array<int, 7>, 64> myarraygc /* 7 x 64 ints */
Can you show two minimal examples of "before and after" so we can compile it ourselves? Is the code being optimized? Is it being stripped of debug symbols?

vector<vector<>> will take up more space because they hold more information and are all separately allocated (I'm not sure of the specifics of std::array), but for a full program this is most likely insignificant compared to the logic of the program itself.

Personally, I usually avoid using 2D vectors and tend to use 1D vectors with y * width + x being the index (4 * y * width + 4 * x for RGBA arrays). Of course, this doesn't work for jagged arrays.
Last edited on
My question is : Is this correct ? The difference in program size seems like a
lot.
Is the code being optimized? Is it being stripped of debug symbols?


# This is the makefile I use.
# makefile starts here copyright anyone who was of help that day :
# 02-01-2018
CXX=g++-7
CXXFLAGS += -std=c++17 -MT $@ -MP -MMD -MF $(@:.o=.d)\
-pedantic-errors -Wall -Wextra
aa: $(patsubst %.cpp,%.o,$(wildcard *.cpp))
$(LINK.cc) $(OUTPUT_OPTION) $^
-include $(patsubst %.cpp,%.d,$(wildcard *.cpp))
# end makefile

[quote] Can you show two minimal examples of "before and after" so we can compile it ourselves?quote]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* much maligned chessboard grid ( 64 squares ) 7 pieces of data for each
   const std::vector<std::vector<int>> myvectorgc /* 7 x 64 ( rows of ints )
   const std::array<std::array<int, 7>, 64> myarraygc /* 7 x 64 ints */

   const std::vector<std::vector<int>> minivectorgc /* 3 x 4 ( rows of ints ) */
       {
        { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }
      };
   /* extra braces and inverted indices yay ! */
   const std::array<std::array<int, 3>, 4> miniarraygc /* 3 x 4 ints */
   {
        {{ 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }}
   }; 

  int main( void )
  {

     return 1;
  } /* fin de Main  >>>>>>>>>>>>>>>>>>>>>>> */


for a 7 x 64 grid the compiled program is 60k ± bigger using a vector
for a 3 x 4 " " " " " 22k ± " " " "
PS I will look into your formula for indices of 1D containers.
Program file bigger when using vector.
So?
My question is : Is this correct ? The difference in program size seems like a
lot.

‘This’ what? And: is 60 Kb a lot?

Loading large executables into memory could become expensive, but for example g++.exe is 1104 Kbytes and in my old notebook starts in a blink. A GUI program will load a lot of libraries and other executables, but, for what I can see, everybody wants GUI programs nowadays. What are your concerns?

two minimal examples … so we can compile it

I think “so we can compile it” meant it should be compilable - your code doesn’t compile even after having added #include <array> and #include <vector>.
Anyway, this code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// #include <array>
#include <vector>


// 3 x 4 ( rows of ints )
const std::vector<std::vector<int>> minivectorgc {
    {  1,  2,  3,  4 },
    {  5,  6,  7,  8 },
    {  9, 10, 11, 12 }
};

// extra braces and inverted indices yay !
// const std::array<std::array<int, 3>, 4> miniarraygc /* 3 x 4 ints */
//                                  ^   ^ This is not consistent with 
//                                        your initialization
//                               \/ \/
// const std::array<std::array<int, 4>, 3> miniarraygc { {
    // {  1,  2,  3,  4 },
    // {  5,  6,  7,  8 },
    // {  9, 10, 11, 12 }
// } };


int main()
{
    return 1;
}

compiled this way:
g++.exe -std=c++2a -Wall -Wextra -pedantic-errors main.cpp -o main.exe
in my W7 machine creates an .exe 525,133 bytes big, while this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <array>
// #include <vector>


// 3 x 4 ( rows of ints )
// const std::vector<std::vector<int>> minivectorgc {
    // {  1,  2,  3,  4 },
    // {  5,  6,  7,  8 },
    // {  9, 10, 11, 12 }
// };

// extra braces and inverted indices yay !
// const std::array<std::array<int, 3>, 4> miniarraygc /* 3 x 4 ints */
//                                  ^   ^ This is not consistent with 
//                                        your initialization
//                               \/ \/
const std::array<std::array<int, 4>, 3> miniarraygc { {
    {  1,  2,  3,  4 },
    {  5,  6,  7,  8 },
    {  9, 10, 11, 12 }
} };


int main()
{
    return 1;
}

creates an .exe 85,869 bytes big.

The difference is 439,264 bytes, that is 429 Kbytes (428.96875).
If I check my ‘vector’ file in …\include\c++\8.1.0, I can see it is 2,747 byte big and includes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stl_algobase.h>      // 50,464 bytes
#include <bits/allocator.h>         //  7,569 bytes
#include <bits/stl_construct.h>     //  7,397 bytes
#include <bits/stl_uninitialized.h> // 27,649 bytes
#include <bits/stl_vector.h>        // 60,488 bytes
#include <bits/stl_bvector.h>       // 33,703 bytes
#include <bits/range_access.h>      // 10,030 bytes
// total                              197,300 bytes

#ifndef _GLIBCXX_EXPORT_TEMPLATE
# include <bits/vector.tcc>
#endif

#ifdef _GLIBCXX_DEBUG
# include <debug/vector>
#endif

#ifdef _GLIBCXX_PROFILE
# include <profile/vector>
#endif 

while ‘array’ is 11,657 bytes, but includes:
1
2
3
4
5
6
7
8
9
#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>
#else

#include <utility>                  // 12,358 bytes
#include <stdexcept>                //  7,975 bytes
#include <bits/stl_algobase.h>      // 50,464 bytes
#include <bits/range_access.h>      // 10,030 bytes
// total                               80,827 bytes 

197,300 + 2,747 = 200,047
80,827 + 11,657 = 92,484
200,047 - 92,484 = 107,563 bytes --> 105 Kb (105.04199219).
Perhaps just this very, very naive analysis accounts for nearly the 25% of the size difference between the two .exes.
Ho, ho, ho. Exactly same code compiles to different size binary on different systems with different version of system libraries. Megabytes of difference.


A vector object has at least a pointer that the array doesn't. However, 7 pointers do not require 60k.

Each function has instructions. They must be stored somewhere. Size of source code does not match amount of instructions. Vector has more and more complex member functions.


1
2
3
4
#include <iostream>
int main() {
  std::cout << "hello";
}

What is in the binary? A lot that we cannot see, but also six bytes for the string literal, and a call of operator<<. Just the call (to library), not the function's instructions.

Implementations from templates are not in dynamically loaded objects. They are in the binary.
I didn't even know std::array existed! Why is it better than cstyle arrays?

Also does file size affect performance at all or just storage?
Last edited on
Hmmm thanks that's interesting. What are disadvantages of arrays degenerating into pointers when passed into functions? Why is that a bad thing?? What I mean is.. you're treating the pointers as you would an array correct?
Ho, ho, ho.


Misquoting Santa himself :)

Program file bigger when using vector. So?


Going into rhetoriks over my QUOTE trivial question UNQUOTE will NOT repeat NOT make me go into a yellow tizzy because :
QUOTE my code does not compile UNQUOTE

This thread is the closest I can get to any exchange of ideas about computing.

So I thank you very much for your input :)
> What are disadvantages of arrays degenerating into pointers when passed into functions?
> Why is that a bad thing??

The basic problem stems from the loss of array size information associated with array to pointer decay. We have to be extra careful and pass number of elements in the array correctly; and if we make a careless mistake, the compiler can't alert us about it.

Stroustrup in 'Programming: Principles and Practice Using C++'
Like arrays, pointers are often overused and misused. Often, the problems people get themselves into involve both pointers and arrays, so we’ll summarize the problems here. In particular, all serious problems with pointers involve trying to access something that isn’t an object of the expected type, and many of those problems involve access outside the bounds of an array.
...
In all cases, the practical problem for the programmer is that the actual access looks perfectly innocent; it is “just” that the pointer hasn’t been given a value that makes the use valid. Worse (in the case of a write through the pointer), the problem may manifest itself only a long time later when some apparently unrelated object has been corrupted.
...
It is common for programmers to underestimate these problems. However, many experienced programmers have been defeated by the innumerable variations and combinations of these simple array and pointer problems. The solution is not to litter your code with pointers, arrays, news, and deletes. If you do, “being careful” simply isn’t enough in realistically sized programs. Instead, rely on vectors, RAII (“Resource Acquisition Is Initialization”; see §19.5), and other systematic approaches to the management of memory and other resources.
Thanks a lot JLBorges you're awesome (as always)! ;)
closed account (E0p9LyTq)
const std::vector<std::vector<int>> myvec;
That creates an empty vector, requires you push_back the elements.

The const modifier makes the container's elements as unmodifiable. You won't be able to push_back any elements or modify existing elements.

You can create a sized std::vector easily (zero filled):
std::vector<std::vector<int>> myvec2(7, std::vector<int>(64));

const std::array<std::array<int, 7>, 64> myarraygc;
That creates a std::array of 64 rows and 7 columns, same as the C-style array: int myarr[64][7];

const creates a std::array with unmodifiable elements.

Creating a 2D std::array you need to reverse order the dimensions:
std::array<std::array<int, 64>, 7> myarr;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
#include <array>

int main()
{
   std::vector<std::vector<int>> vec1; /* NOT 7 x 14 ints, empty vector */

   // trying to access the 2nd dimension will abnormally terminate the program.
   std::cout << vec1.size() /* << vec1[0].size()*/ << "\n\n";

   std::vector<std::vector<int>> vec2(7, std::vector<int>(14));  /*  THIS is 7 x 14 */

   for (auto const& x : vec2)
   {
      for (auto const& elem : vec2[0])
      {
         std::cout << elem << ' ';
      }
      std::cout << '\n';
   }

   std::cout << vec2.size() << ' ' << vec2[0].size() << "\n\n";

   std::array<std::array<int, 7>, 14> arr1 {}; /* NOT 7 x 64 ints */

   for (auto const& x : arr1)
   {
      for (auto const& elem : arr1[0])
      {
         std::cout << elem << ' ';
      }
      std::cout << '\n';
   }
   std::cout << '\n';

   std::cout << arr1.size() << ' ' << arr1[0].size() << "\n\n";


   std::array<std::array<int, 14>, 7> arr2 {}; /* THIS is 7 x 14 ints */

   for (auto const& x : arr2)
   {
      for (auto const& elem : arr2[0])
      {
         std::cout << elem << ' ';
      }
      std::cout << '\n';
   }

   std::cout << arr2.size() << ' ' << arr2[0].size() << '\n';
}


Last edited on
closed account (E0p9LyTq)
Grime wrote:
I didn't even know std::array existed!

Added in C++11. If you are using Turbo C you won''t be able to use it.
And that's why I don't use turbo c++ outside school hours..
Topic archived. No new replies allowed.