8

This is pretty farfetched, but is the following code "safe" (i.e. guaranteed not to cause segmentation fault):

std::vector<int> vec(1); // Ensures that &vec[0] is valid
vec.reserve(100);
memset(&vec[0], 0x123, sizeof(int)*100); // Safe?

I realize that this is ugly - I'm only interested to know if it's technically safe, not "pretty". I guess its only usage could be to ignore values stored beyond a given index.

Note! How can I get the address of the buffer allocated by vector::reserve()? covers the same topic, but I'm more interested if this is safe and if there are pitfalls doing this.

EDIT: Original code was wrong, replaced original memcpy with memset.

Community
  • 1
  • 1
larsmoa
  • 12,604
  • 8
  • 62
  • 85
  • 1
    Ok, this is so ugly that it hurts. Why are you doing that? Can't you simply use an array, if you really have to? In this example 100 is fixed, so you could use an array on the stack without even delete[]ing... – Francesco Nov 22 '11 at 14:43
  • 2
    "Segmentation fault" is a platform-specific event. The C++ language doesn't describe what it is. The language only says whether something is defined, and if so, to do what. – Rob Kennedy Nov 22 '11 at 15:16
  • 1
    I have downvoted the question, not because I consider it a bad question, but because you did not take enough time to ensure that what you were asking was what you meant to ask (the original code and the code in the current version are quite different). -2 rep points are not much, but should remind you in the future to be slightly more careful, as when you ask other people take the time to answer trying to help, and it is that time that gets wasted if you reformulate the question later on. – David Rodríguez - dribeas Nov 22 '11 at 15:43
  • If only considering the 3 lines of code here, I believe my answer in https://stackoverflow.com/questions/19064318/ showed the code is well-defined. – wpzdm Sep 20 '21 at 15:03

4 Answers4

18

No, it is not safe.

After a reserve(), the vector is guaranteed not to reallocate the storage until the capacity() is reached.

However, the standard doesn't say what the vector implementation can do with the storage between size() and capacity(). Perhaps it can be used for some internal data - who knows? Perhaps the address space is just reserved and not mapped to actual RAM?

Accessing elements outside of [0..size) is undefined behavior. There could be some hardware check for that.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • upped for pointing out _why_ this is a bad idea: the reserved memory is UB and not available 'officially' via the vector until it has been `resize`d or `push`/`emplace`d to. – underscore_d Nov 18 '15 at 11:28
2

Vector-reallocation invalidates existing pointers, references etc. Reserve could trigger a reallocation (23.3.6.2, [vector.capacity]) but you are taking the address of the first element after the eventual reallocation (which in this case will not probably happen at all, but that's besides the point). So I see no problem with the code.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
Francesco
  • 3,200
  • 1
  • 34
  • 46
2

First note that your memset will truncate the 0x123 to a single byte and write that, not writing a four byte pattern.

Then, don't do that, just use the container: std::vector<int> vec(100, whatever_value_you_want);

However to answer the question it may appear to work specifically for POD types if the compiler doesn't use the allocated space for anything. Certainly if anyone calls resize, insert, push_back etc it'll blow away whatever you've already written into the memory and the size of the vector will be wrong as well. There's just no reason to write such code.

Mark B
  • 95,107
  • 10
  • 109
  • 188
1

I believe the accepted answer is incorrect.

If the content of the vector is POD type (e.g., int as in the question, orchar etc.), then reserve()ed memory is well-behaved objects, and the standard ensures nothing unexpected should be done to storage between size() and capacity().

My argument, with quotation and reference to the Standard, was given in my answer https://stackoverflow.com/a/69141237/2791230. Here, I show in particular why the concerns in the accepted answer cannot happen.

“Perhaps [reserve()ed memory] can be used for some internal data.” No, it can not be. Consider insert() elements to the end of the vector, until reserve()ed memory is filled up. The Standard ensures there are no side effects other than the apparent filling (and its results, e.g., changing size()). Thus, it would be contrary to the Standard if some internal data are overwritten by insert() (which is of course a side effect).

“Perhaps the address space is just reserved and not mapped to actual RAM?” This is more obviously impossible, because there are already objects living in the reserve()ed memory, see the referred answer for detail.

In general, I think people are too ready to claim something is UB. Unless reference is given that the Standard explicitly says something is UB, all claims that “it is UB” should mean “I do not know it is defined, so I think it is UB,” because UB means “it is nowhere defined in the whole Standard.”

wpzdm
  • 134
  • 1
  • 11
  • Your claim in the second last para is incorrect. Modern operating systems routinely use lazy allocation of memory when doing dynamic memory allocation - and only actually DO the allocation when the memory is used in some non-trivial way (e.g. it is overwritten, a constructor called to initialise, etc). The C++ standard also does not require that any objects "live" in memory managed by a vector - reserved or otherwise - other than the elements with indices `0` to `.size()-1`. – Peter Dec 03 '21 at 04:28