-1

I'm reading about struct with flexible array members and I wrote a little program to test my understanding:

struct HelloWorld {
    int a;
    std::string b;
};

std::string arr[5] = { "abcdetttttttttttttttttttttttttt", 
                       "abcdefgh", "abcrrrr", "abcdtttttttt",
                       "abcdezzzzzzzz" };
HelloWorld * h = new HelloWorld[5];
for (int i = 0; i < 5; i++) {
    std::cout << (h+i) << std::endl;
    h[i].a = 5;
    h[i].b = arr[i];
}
for (int i = 0; i < 5; i++) {
  std::cout << (h + i) << std::endl;
}

First of all, I read that the flexible array member, in this case the string b, is not counted toward the size of the struct when using sizeof. However, when I calculate sizeof HelloWorld it returns 48 bytes. Shouldn't it be just 4 bytes? Secondly, When I dynamically allocate an array of 5 HelloWorld, each object's adress is separated by 48 bytes. Even when I fill the member b with different-sized string, these addresses dont change, so I'm guessing the struct is storing the strings somewhere else and not in the allocated space by "new". Where are these strings being stored?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Harry Kane
  • 163
  • 1
  • 7
  • 10
    "flexible array member" is a C thing. It doesn't exist in C++. – Mat Jan 08 '19 at 21:04
  • 6
    Why do you think `std::string b` is a flexible array member? – NathanOliver Jan 08 '19 at 21:04
  • `std::string b;` is just a single `string`. It's not an array. – Algirdas Preidžius Jan 08 '19 at 21:05
  • 2
    hit pause, rewind and play again. Maybe from a better source, a better book. You started on a wrong path to learn C++. – bolov Jan 08 '19 at 21:05
  • @NathanOliver so a string is size is the same no matter how long the string is? I dont understand – Harry Kane Jan 08 '19 at 21:06
  • I feel obliged to mention that you should get [a good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list?lq=1) – Rob K Jan 08 '19 at 21:06
  • `sizeof()` is a compile time constant. – drescherjm Jan 08 '19 at 21:06
  • 2
    [std::string](https://en.cppreference.com/w/cpp/string/basic_string) is a class which stores (possibly) dynamically allocated character data. It is NOT an array. – Rob K Jan 08 '19 at 21:07
  • ***However, when I calculate sizeof HelloWorld it returns 48 bytes. Shouldn't it be just 4 bytes?*** No `std::string` has a fixed size. It should be larger than 4 itself. – drescherjm Jan 08 '19 at 21:07
  • 1
    Yes, `sizeof(std::string)` is always the same. `std::string` allocates the memory it needs dynamically so it only stores a pointer to it (actually more but we really don't need to get into that yet). – NathanOliver Jan 08 '19 at 21:07
  • 1
    ***Even when I fill the member b with different-sized string, these addresses dont change, so I'm guessing the struct is storing the strings somewhere else and not in the allocated space by "new".*** std::string will allocate memory for the string when it needs to do so. It will use new to do this. – drescherjm Jan 08 '19 at 21:09
  • 4
    Let me add that you should forget _everything_ you know about C. At one time, C++ could be considered a superset of C, but this is no longer so. – Rob K Jan 08 '19 at 21:12
  • C and C++ : *Very* different languages. – Jesper Juhl Jan 08 '19 at 21:31
  • 1
    `sizeof(string)` is not 0, so `sizeof(HelloWorld)` can't be 4 (assuming `sizeof(int)=4`). At a *minimum*, a `string` must be `sizeof(void*)` if it stores ALL its data in dynamic memory (rare). Typically the size is closer to `sizeof(char*)+sizeof(size_type*2)` as the `size` and `capacity` are stored in the `string` itself` while the `char*` points at the payload elsewhere in memory. Modern libraries use [Small String Optimization](https://stackoverflow.com/questions/10315041/) to store small payloads directly in the `string` itself (which is why `sizeof(string)` is so large in your case). – Remy Lebeau Jan 08 '19 at 23:11
  • @RobK It's still approximately true. – user253751 Jan 09 '19 at 00:19

1 Answers1

4

It seems that you are mixing up the two different languages C and C++, and you are trying out the concept of flexible array members available in C within the language C++, where this concept does not exist at all.

A brief example of flexible array members in C, taken from cppreference.com, yet shortened a bit:

If a struct defines at least one named member, it is allowed to additionally declare its last member with incomplete array type...

struct s { int n; double d[]; }; // s.d is a flexible array member 
struct s *s1 = malloc(sizeof (struct s) + 64); // as if d was double d[8]
s1->d[0] = 1.0;
s1->d[1] = 2.0;

So with a flexible array member, you can individually create smaller or larger struct s-objects as you like while still being able to use the notation s.d[x] to access the members of that array.

In language C++, in contrast, a definition like struct s { int n; double d[]; } is illegal as C++ simply does not support flexible array members. In C++, you will solve such issues by using a dynamic collection data type as member:

struct s {
   int n;
   std::vector<double> d;
} s1;
...
s1.d.push_back(1.0);
s1.d.push_back(2.0);
s1.d[0] += 10;
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58