IT Share you

std :: begin 및 std :: end가 "메모리 안전하지 않은"이유는 무엇입니까?

shareyou 2021. 1. 10. 19:20
반응형

std :: begin 및 std :: end가 "메모리 안전하지 않은"이유는 무엇입니까?


에서 이 블로그 게시물 , 에릭 Niebler는 말한다 :

std :: begin 및 std :: end의 문제점은 무엇입니까? 놀라다! 메모리 안전하지 않습니다. 이 코드의 기능을 고려하십시오.

extern std::vector<int> get_data();
auto it = std::begin(get_data());
int i = *it; // BOOM

std :: begin에는 const 및 non-const lvalue에 대해 두 개의 오버로드가 있습니다. 문제는 rvalue가 const lvalue 참조에 바인딩되어 위의 dangling iterator로 이어진다는 것입니다.

나는 그의 요점을 이해하는 데 어려움이 있으며 왜 it매달린 참조가 있습니다. 누군가 설명 할 수 있습니까?


get_data함수는 객체를 반환합니다. 표시된 방식으로 사용하면 해당 객체는 임시 객체가되며 전체 표현식이 종료되면 삭제됩니다. 이터레이터는 이제 더 이상 존재하지 않는 벡터 객체를 참조하며 역 참조하거나 유용한 방법으로 사용할 수 없습니다.


Eric의 요점은 시작하는 인수로 rvalue 컨테이너를 std::begin조용히 받아들이 는 것입니다. 표면적으로는 코드 문제도 다음과 같이 예시됩니다.

auto it = get_data().begin();

그러나 std::begin무료 함수 템플릿이므로 각 컨테이너의 begin멤버에 적절한 참조 한정자를 추가 할 필요없이 rvalue를 거부하도록 만들 수 있습니다 . "단지"포워딩으로 코드에 메모리 안전 계층을 추가 할 기회를 놓치게됩니다.

이상적으로, 과부하 세트

template< class C > 
void begin( C&& ) = delete;

이로 인해 블로그 게시물의 코드가 그 자리에서 거부되었을 것입니다.


에서 반환 된 임시 벡터 는 완료된 get_data후 범위를 벗어 std::begin납니다. 살아있는 상태로 유지되지 않으므로 it파괴 된 객체에 대한 반복자도 마찬가지 입니다.


이것이 std :: begin의 메모리 안전 실패라고 말하는 것이 공평합니까? 컨테이너가 삭제 된 후 포인터를 따라가는 것이 유효하도록 반복기를 만드는 '안전한'방법은 없습니다.

다른 메서드에 대한 검사는 없지만 범위 파생 반복기를 팝업으로 만들 수있는 방법이없는 것과는 다릅니다. 좀 더 노력하면 돼 ...


rvalue에서 초기화를 허용하기 때문에 좋지 않습니다.


사실, 복잡한 기능은 다음과 같은 두 가지 짧은 기능으로 단순화 할 수 있습니다.

int& foo(int x){
   return x;
}
int generate_a_int(){
   return 42;
}

그런 다음 그것을 호출하면 foo(generate_a_int())임시 값이 생성되고 함수 본문에서 일단 생성 된 임시 값 generate_a_int()이 파괴되고 매달린 참조가 발생합니다.

이제 이해가 되나요?

참조 URL : https://stackoverflow.com/questions/54625792/why-are-stdbegin-and-stdend-not-memory-safe

반응형