Date: Sun, 31 Mar 2024 16:09:43 +0000
Actually, after a closer look at this.
There’s two ways on how the relocation can take place:
1. It can expand the underlying buffer. In which case contents aren’t moved and no references are invalidated in practice.
2. It needs to create a new buffer and then move the content into the new space.
But before the contents are moved, you are in an intermediate situation where you have two buffers, if the last position of the buffer is inserted before moving the previous content, the reference would technically still be valid. And then you can move the old content into a new buffer, thus invalidating the reference, but at that point the object has already been copied.
There’s nothing that is stopping a library implementer from implementing it this way. Which would make the application behave in a valid way if this situation ever occurred.
But as stated, this would only work for push_back. And in my perspective, I have never seen this particular case.
It would definitely make code safer, not sure if it is worth restricting library implementers to this exact algorithm.
It is not meritless, there’s something to it.
From: Tiago Freire
Sent: Sunday, March 31, 2024 5:52 PM
To: std-proposals_at_[hidden]
Cc: Avi Kivity <avi_at_[hidden]>
Subject: RE: [std-proposals] When does vector::push_back() invalidation happen?
I don’t know how it could push before reallocating if reallocating needs to take place. I.e. you don’t have the space to put the new element so where are you going to put it?
Regarding your question, its all references, there are no copies up until when the element is inserted onto the new location, that this should be considered dangerous seems to me to be a no-brainer. But I don’t think it requires any further explanation.
It should be seen as any different to:
Int& temp = v.back();
v.push_back(temp);
Best regards,
From: Std-Proposals <std-proposals-bounces_at_[hidden]<mailto:std-proposals-bounces_at_[hidden]>> On Behalf Of Avi Kivity via Std-Proposals
Sent: Sunday, March 31, 2024 5:22 PM
To: std-proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>>
Cc: Avi Kivity <avi_at_scylladb.com<mailto:avi_at_[hidden]>>
Subject: [std-proposals] When does vector::push_back() invalidation happen?
Consider:
std::vector<int> v;
v.push_back(41);
v.push_back(v.back());
The second push_back() can cause the vector to reallocate. If it reallocates before executing the push_back(), then performs the push_back(), then it will use-after-free its argument. If it reallocates after the push_back(), and the move constructor can throw, then we lose the strong exception guarantee.
The standard says:
> Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence, as well as the past-the-end iterator.
So, it says nothing about whether a push_back referring to a vector element is legal.
Is this undefined behavior? Should it be specified to work? Should it be noted that it is dangerous?
There’s two ways on how the relocation can take place:
1. It can expand the underlying buffer. In which case contents aren’t moved and no references are invalidated in practice.
2. It needs to create a new buffer and then move the content into the new space.
But before the contents are moved, you are in an intermediate situation where you have two buffers, if the last position of the buffer is inserted before moving the previous content, the reference would technically still be valid. And then you can move the old content into a new buffer, thus invalidating the reference, but at that point the object has already been copied.
There’s nothing that is stopping a library implementer from implementing it this way. Which would make the application behave in a valid way if this situation ever occurred.
But as stated, this would only work for push_back. And in my perspective, I have never seen this particular case.
It would definitely make code safer, not sure if it is worth restricting library implementers to this exact algorithm.
It is not meritless, there’s something to it.
From: Tiago Freire
Sent: Sunday, March 31, 2024 5:52 PM
To: std-proposals_at_[hidden]
Cc: Avi Kivity <avi_at_[hidden]>
Subject: RE: [std-proposals] When does vector::push_back() invalidation happen?
I don’t know how it could push before reallocating if reallocating needs to take place. I.e. you don’t have the space to put the new element so where are you going to put it?
Regarding your question, its all references, there are no copies up until when the element is inserted onto the new location, that this should be considered dangerous seems to me to be a no-brainer. But I don’t think it requires any further explanation.
It should be seen as any different to:
Int& temp = v.back();
v.push_back(temp);
Best regards,
From: Std-Proposals <std-proposals-bounces_at_[hidden]<mailto:std-proposals-bounces_at_[hidden]>> On Behalf Of Avi Kivity via Std-Proposals
Sent: Sunday, March 31, 2024 5:22 PM
To: std-proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>>
Cc: Avi Kivity <avi_at_scylladb.com<mailto:avi_at_[hidden]>>
Subject: [std-proposals] When does vector::push_back() invalidation happen?
Consider:
std::vector<int> v;
v.push_back(41);
v.push_back(v.back());
The second push_back() can cause the vector to reallocate. If it reallocates before executing the push_back(), then performs the push_back(), then it will use-after-free its argument. If it reallocates after the push_back(), and the move constructor can throw, then we lose the strong exception guarantee.
The standard says:
> Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence, as well as the past-the-end iterator.
So, it says nothing about whether a push_back referring to a vector element is legal.
Is this undefined behavior? Should it be specified to work? Should it be noted that it is dangerous?
Received on 2024-03-31 16:09:48