7

I have the following C++ code:

#include <string>
#include <iostream>


int main(int argc, char** argv)
{
    int size;
    std::string strArray[3];
    std::string str0 = "String 0";
    std::string str1 = "String 1";
    std::string str2 = "String 2";

    strArray[0] = str0;
    strArray[1] = str1;
    strArray[2] = str2;

    for (int i = 0; i < 3; i++)
    {
        std::cout << strArray[i] << std::endl;
    }

    str1.resize(200, 'a');

    for (int i = 0; i < 3; i++)
    {
        std::cout << strArray[i] << std::endl;
    }

    std::cout << str1 << std::endl;

    std::cin.get();
    return 0;
}

The idea here is that I have an array which is a contiguous block of memory, where each member is a std::string, which are mutable and therefore variable in size. I expected this code to break since I resize str1 to take up loads more space than original, and therefore "overflowing" into str2.

Instead I get this output:

String0

String1

String2

String0

String1

String2

String1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...

I have two questions about this. First of all, how is it that increasing the size of str1 and adding loads of characters to it does not flow over into str2 even though they should be in a contiguous block of memory?

Second, how come when I print the array for the second time after resizing str1 AND add the characters to it it still prints the original str1? I have a feeling that this will have something to do with the answer to my first question but I can't quite see what is going on here.

Shog9
  • 156,901
  • 35
  • 231
  • 235
Noodles
  • 73
  • 3
  • The strings in the array are different strings to `str1`, `str2`, `str3`. Even if they weren't, one string wouldn't overflow into the other. Otherwise nobody would ever use the `std::string` class. – juanchopanza Sep 17 '14 at 22:20
  • The interned data of the `std::string` class is allocated on the heap. – πάντα ῥεῖ Sep 17 '14 at 22:20
  • It should be noted that changing `str1` is not the same as changing `strArray[1]`. – MARS Sep 17 '14 at 22:24

3 Answers3

8

The array of string objects is contiguous, but the actual string data is stored on the heap*, so the string data itself is not stored contiguously.

* Actually given an implementation that uses the 'small string optimization' the data is contiguous, stored inside the string objects as long as it's small enough to fit. 'String0' is small enough for all the SSO implementations I know of. Once the data grows past what can be stored in-place the implementation moves it onto the heap.

The reason that modifying str1 does not affect the result of printing strArray[1] is that they are distinct objects with no relation, except that you initialized strArray[1] with the value of str1. This is just like doing:

int intArray[3];
int int0 = 0;
int int1 = 1;
int int2 = 2;

intArray[0] = int0;
intArray[1] = int1;
intArray[2] = int2;

int1 = 10000000; // does not modify intArray[1]

The idea here is that the usual behavior for objects in C++ is the same as for 'primitive types' or 'value types' you may be familiar with in other languages. It's possible to implement other behaviors in C++, but std::string is a regular type.

bames53
  • 86,085
  • 15
  • 179
  • 244
2

As barnes53 pointed out, the array of string only stores the string object, and can simply hold a pointer to the array of characters that represent the string.

The answer to the second question is that the array assignment is done by value rather than by reference, which implies that a copy of the string is made. That is why modifying the original string as no effect on the array version.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • @Jay, There are many different ways of phrasing something, and we can let the OP decide what he prefers. While we both understand that we are expressing the same idea, the OP might find one explanation more clear than another. – merlin2011 Sep 17 '14 at 22:26
1

The array is contiguous the strings are not.

You say str1.resize(200, 'a'); which has no effect on the array because the array contains the value of what str1 used to be not the reference.

So the array value doesn't get overflowed because the value inside the array never changed.

Jay
  • 2,656
  • 1
  • 16
  • 24
  • The array value wouldn't get overflowed even if the array value was resized. `resize` allocates new memory if required, a `std::string` can never "overflow" – M.M Sep 17 '14 at 23:08
  • I was just saying that arr[0] never changed so It can't be overflowed. – Jay Sep 17 '14 at 23:27