이동 한 컨테이너를 재사용 하시겠습니까?


84

이동 된 컨테이너를 재사용하는 올바른 방법은 무엇입니까?

std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);

// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize

container.push_back(2);
assert(container.size() == 1 && container.front() == 2);

C ++ 0x 표준 초안에서 읽은 내용에서; ver3은 올바른 방법 인 것 같습니다. 이동 후 개체가

"달리 명시되지 않는 한, 이러한 이동 된 객체는 유효하지만 지정되지 않은 상태로 배치됩니다."

"다른 방법으로 지정"된 인스턴스를 찾지 못했습니다.

비록 ver3가 약간 원형이고 ver1을 선호하지만 vec3는 추가 최적화를 허용 할 수 있지만 다른 한편으로는 쉽게 실수로 이어질 수 있습니다.

내 가정이 맞습니까?


4
clear전제 조건이 없으므로을 호출 할 수 있습니다 (따라서 객체의 상태에 의존하지 않음).
Nicol Bolas 2012

@Nicol : std::vector크기에 대한 포인터를 저장 한 구현이 있다고 가정 해 봅시다 (어리석은 것처럼 보이지만 합법적입니다). 해당 벡터에서 이동하면 포인터가 NULL로 남아있을 수 있으며 그 후에 clear는 실패합니다. operator=실패 할 수도 있습니다.
Ben Voigt 2012

9
@Ben : "유효하지만 지정되지 않음"의 "유효"부분을 위반하는 것 같습니다.
ildjarn

1
@ildjarn : 소멸자를 실행하는 것이 안전하다는 것을 의미한다고 생각했습니다.
Ben Voigt 2012

질문은 "유효"란 무엇입니까?
ronag

답변:


97

"유효하지만 지정되지 않은 상태"사양의 섹션 17.3.26에서 :

객체의 불변성이 충족되고 객체에 대한 작업이 해당 유형에 대해 지정된대로 동작하는 것을 제외하고 지정되지 않은 객체 상태 [예 : x유형 의 객체 가 std::vector<int>유효하지만 지정되지 않은 상태 인 x.empty()경우 무조건 x.front()호출 될 수 있으며 호출 될 수 있음 x.empty()false를 반환 하는 경우에만 . -예제 종료]

따라서 개체는 라이브입니다. 사전 조건이 필요하지 않은 모든 작업을 수행 할 수 있습니다 (먼저 사전 조건을 확인하지 않는 한).

clear예를 들어에는 전제 조건이 없습니다. 그리고 객체를 알려진 상태로 되돌립니다. 그래서 그것을 지우고 정상적으로 사용하십시오.


표준에서 std :: vector 메소드에 대한 "전제 조건"에 대해 읽을 수있는 곳은 어디입니까?
ronag

1
@ronag : §23.2에는 테이블이 나열되어 있습니다.
Grizzly

2
흥미로운 내용 인 open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.html 을 찾았습니다 .
ronag

4
@ronag : 1) 컨테이너가 유효한 상태이면 호출 clear이 유효합니다. 2) 컨테이너 지정되지 않은 상태에있는 동안 호출 clear은 표준 (§23.2.3 테이블 100)에서 사후 조건을 의무화했기 때문에 컨테이너를 지정된 상태로 만듭니다. 항상 유효한 std::vector<T>클래스 불변이 있습니다 push_back()( T가있는 한 CopyInsertable).
ildjarn

3
@ronag : open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.html은 "빈 것보다 비어있는 것"이라는 인용문에 대한 전국적인 의견 중 하나를 인용했습니다. 국가 기관의 의견이 잘못되었습니다. N3241은 그러한 상태를 제안하지 않았습니다. std :: container의 구현이 move-from으로 인해 "빈 것보다 비어있는"상태를 가지면 해당 상태는 유효한 상태 여야합니다 (즉, 전제 조건이 필요하지 않은 객체로 무엇이든 할 수 있음).
Howard Hinnant 2012

11

객체가 유효하지만 정의되지 않은 상태 라는 것은 기본적으로 객체의 정확한 상태가 보장되지는 않지만 유효하며 이러한 멤버 함수 (또는 멤버가 아닌 함수)가 의존하지 않는 한 작동하도록 보장됨을 의미합니다. 특정 상태를 가진 개체에.

clear()멤버 함수이므로 개체에서 이동 - 호출 할 수있다 (이것은 물론 유효 이외) 객체의 상태에 아무런 전제 조건이 없다. 다른 한편으로, 예를 들어 front()컨테이너가 비어 있지 않은지에 따라 다르므로 비어 있지 않다는 보장이 없으므로 호출 할 수 없습니다.

따라서 ver2와 ver3 모두 괜찮습니다.


벡터는 항상 비어 있지만 일반적인 경우에는 해당되지 않습니다. (IE 배열)
Mooing Duck

"벡터는 항상 비어있을 것입니다", 무엇을 기반으로합니까?
ronag

1
@ronag : 물론 ver2와 ver3을 의미했습니다 (텍스트에서 명확해야하는 것처럼 오타 수정
Grizzly

흥미롭게도에 대한 전제 조건 front()은에 대해서만 명시 std::array되어 있으며 표에는 없습니다.
Ben Voigt

1
@Ben : §23.2.3 테이블 100은의 작동 의미가 front()다음 *a.begin()과 같고, §23.2.1 / 6은 " 컨테이너가 비어 있으면begin() == end() ", §24.2.1 / 5는 " 라이브러리가 과거를 가정하지 않습니다. 끝 값은 역 참조 가능합니다. ". 결과적 front()으로 더 명확하게 할 수 있지만에 대한 전제 조건을 추론 할 수 있다고 생각합니다 .
ildjarn

-8

나는 당신이 이동 된 객체로 (파괴를 제외하고) 아무것도 할 수 없다고 생각합니다.

swap이동의 모든 이점을 얻으면서 컨테이너를 알려진 상태로 두는 대신 대신 사용할 수 없습니까 ?


+1. swap은 좋은 생각이지만 모든 경우에 작동하지는 않습니다. 예를 들어 auto를 사용하면 작동하지 않습니다. 내부적으로 스왑을 사용하는 safe_move가 아이디어가 될 수 있습니까?
ronag

5
그것은 라이브 객체이며, 전제 조건이없는 모든 기능을 사용할 수 있습니다 (불변성 제외)
Mooing Duck

의 기본 템플릿 std::swap에는 2 개의 이동 할당이 있으며 해당 할당의 대상은 값에서 이동됩니다. 그것은 나에게 "이동 된-에서 객체에 어떤 일을"로 계산
Caleth
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.