문제

Today I wrote something which looked like this:

void foo(std::vector<char>&v){
    v.push_back('a');
    char*front=&v.front();
    char*back=&v.back();
    size_t n1=back-front+1;
    v.push_back('b');//This could reallocate the vector elements
    size_t n2=back-front+1;//Is this line valid or Undefined Behavior ?
}

If a reallocation occures when I push 'b' back, may I still compute the difference of my two pointers ?

After reading the relevant passage of the standard a few times, I still cannot make my mind on this point.

C++11 5.7.6: When two pointers to elements of the same array object are subtracted, the result is the difference of the subscripts of the two array elements. The type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff_t in the header (18.2). As with any other arithmetic overflow, if the result does not fit in the space provided, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i − j provided the value fits in an object of type std::ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object. Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.

Of course I know that it works, I just wonder if it is legal.

도움이 되었습니까?

해결책

Pointers to deleted objects are toxic: don't touch then for anything other than giving them a new value. A memory tracking system may trap aby use of a reclaimed pointer value. I'm not aware if any such system in existence, however.

The relevant quote is 3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 4:

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value, the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers to any part of the deallocated storage. The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined.

When resizing a std::vector<...> it jumps through a number of hoops (allocators) and, by default, eventually calls a deallocation function.

다른 팁

Strictly speaking, it's UB. But you can always convert your char * pointers to uintptr_t (provided it is present) and then safely subtract the resulting integers.

void foo(std::vector<char>&v){
    v.push_back('a');
    auto front= uintptr_t (&v.front());
    auto back = uintptr_t (&v.back());
    size_t n1=back-front+1;
    v.push_back('b');//This could reallocate the vector elements
    size_t n2=back-front+1;
}

This particular case is safe but ugly and misleading.

Line v.push_back('b');//This could reallocate the vector elements can cause reallocation of your container. In this case next line will use a non existent front and back pointers. Computing difference of two addresses is safe even if are dangling pointers. What is not safe is dereferencing them.

The correct solution is to use vector::count() function the will be always in sync. If you (for some reason) don;t want to call vector::count() you should at leas use ++n1.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top