Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is accessing the raw pointer after std::vector::reserve safe?

Tags:

c++

stl

vector

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.

like image 775
larsmoa Avatar asked Nov 22 '11 14:11

larsmoa


4 Answers

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.

like image 63
Bo Persson Avatar answered Oct 17 '22 05:10

Bo Persson


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.

like image 30
Francesco Avatar answered Oct 17 '22 06:10

Francesco


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.

like image 38
Mark B Avatar answered Oct 17 '22 04:10

Mark B


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.”

like image 34
wpzdm Avatar answered Oct 17 '22 06:10

wpzdm