2010-03-01 8 views
6

결과를 계산하는 임의의 수의 작업자 개체를 std::vector으로 생성하는 클래스가 있습니다. 특정 지점에서 일부 작업자 개체를 제거 하겠지만 그 결과를 spawned 클래스에만 알려진 특정 순서로 유지하고 싶습니다. 따라서 클래스 A의 출력 벡터를 제공하고 있습니다.반복자 대 참조 포인터 대

나는 (IMO) 세 가지 옵션이 있습니다. 벡터, 참조 또는 반복자에 대한 포인터를 멤버로 가질 수있었습니다. iterator 옵션에는 특정 draw back이 있습니다 (iterator가 증가 될 수 있습니다.) 포인터 나 참조가 명확하면 확실하지 않습니다. NULL이 될 수 없으며 cruncher가 벡터가 있어야하기 때문에 참조가 더 좋습니다.

가장 확실하지 않은 것은 참조의 유효성입니다. std::list< std::vector<int> >의 일부 작업으로 해당 광고가 무효화됩니까? 이러한 작업은 std::list의 반복자를 무효화하는 것과 동일합니까? 지금 당장 볼 수없는 또 다른 접근법이 있습니까? 또한 컨테이너에 대한 결합은 옳지 않습니다. 특정 컨테이너를 Cruncher 클래스로 강제합니다. 명확성을 위해 제공

코드 : 반복자가 무효화

#include <list> 
#include <vector> 
#include <boost/ptr_container/ptr_list.hpp> 

class Cruncher { 
    std::vector<int>* numPointer; 
    std::vector<int>& numRef; 
    std::list< std::vector<int> >::iterator numIterator; 
public: 
    Cruncher(std::vector<int>*); 
    Cruncher(std::vector<int>&); 
    Cruncher(std::list< std::vector<int> >::iterator); 
}; 

class A { 
    std::list< std::vector<int> > container; 
    boost::ptr_list< std::vector<int> > container2; 
    std::vector<Cruncher> cruncherList; 
}; 

답변

6

경우, 그것은 또한 반복자로 변환되었다는 포인터/참조를 무효화한다. 이 경우 : 반복자가 무효화되는 경우 (예를 들어 기존의 모든 벡터 반복자를 무효화 할 수와 push_back을 호출)

std::vector<T>::iterator it = ...; 
T *p = &(*it); 
T &r = *p; 

를, 포인터 및 참조는 무효가됩니다. 표준 23.2.4.2/5 (벡터 용량) 발

:

주 : 재 할당 시퀀스의 요소들에 참조 된 모든 참조 포인터 반복자 무효화.

std :: list에 대해 동일한 일반 원칙이 적용됩니다. 반복기가 무효화되면 반복기가 변환되는 포인터와 참조도 무효화됩니다.

std :: list와 std :: vector의 차이점은 반복기 무효화의 원인입니다. std :: list iterator는 참조하는 요소를 제거하지 않는 한 유효합니다. 따라서 std::vector<>::push_back은 반복자를 무효화 할 수 있으므로 std::list<>::push_back은 반복 할 수 없습니다. 다음 부모의 벡터의 내용이 당신의 작업자 스레드를 산란 후 재 할당하는 경우

+0

stord :: list를 사용하여 견본. 목록의 무효화를 설명하는 섹션으로 표준 인용문을 변경하면 답변이 정상입니다. – pmr

+0

@pmr - 목록에 대한 추가 정보를 포함하도록 내 대답을 업데이트했습니다. –

1

, 자신의 포인터, 참조, 반복자, 또는 무엇이든은 거의 확실 무효 있습니다. 목록은 다를 수 있습니다 (할당 방법을 고려할 때). 그러나 모르겠습니다. 플랫폼에 따라 다를 수도 있습니다.

기본적으로 작업자 스레드가 여러 개있는 경우 실제로 복사가 과중하지 않는 한 결과를 다시 덤프하는 부모 클래스에 대한 메서드가 실제로있는 것이 가장 안전합니다. 물론 부모에게 직접 할당하는 것만 큼 좋지는 않지만, 덤핑하는 컨테이너가 재 할당시 "손실"되지 않도록해야합니다.

회원이 추가 (또는 삭제) 될 때 사용하고있는 목록이 "다른"공간을 다시 할당하지 않는다고 보장하면 원하는 것을 얻을 수 있지만 벡터는 확실히 안전하지 않습니다.그러나 어느 쪽이든, (포인터, 참조 또는 반복자) (아마도)에 액세스하는 방법은 "루트 컨테이너"가 내용을 이동하지 않는 한 그렇게 중요하지 않습니다.

편집 :

목록이 삽입 및 접합이 을하지 않는 중요한 속성이 있습니다 :

아래 설명에서 언급 한 바와 같이

, 여기 SGI's website (강조 광산)에서 목록에 대한 블록이야 요소를 나열하도록 반복기를 무효화하고 심지어 제거 만 제거하면 요소를 가리키는 반복자 만 만 무효화됩니다. 반복자의 순서는 (즉, 목록 :: 반복자는 이전 을보다 목록 작업 후 다른 전임자 나 후임자 을 가있을 수 있습니다) 변경 될 수 있지만, 반복자 자체가 무효화하거나 할 수 없습니다 이 무효화 또는 돌연변이가 인 경우를 제외하고는 다른 요소를 가리 킵니다.

그래서 이것은 기본적으로 그 자체로 덤프 할 수와 각 직원 "마스터 저장소로 목록을 사용합니다"라고하고, 다른 근로자가 완전히 완료되면 무효가되지 않습니다 알고 자신의 벡터는 삭제됩니다 명부.

+0

리스트 반복자는 현재 가리키는 요소가 지워지지 않는 한 유효합니다. – James

+0

당신은 맞습니다, 자동 작성. 저자는 목록에 대한 단락에서 http://stackoverflow.com/questions/1436020/c-stl-containers-whats-the-difference-between-deque-and-list/1436038#1436038을 참조 할 수 있습니다. – fogo

+0

@ fogo : 감사합니다. SGI의 사이트에서 텍스트를 추가하기 위해 OP를 편집했습니다. –

0

현재 버전의 C++ (즉, 이동 생성자 없음)에서 std :: list에 포함 된 항목에 대한 포인터는 목록 반복기와 함께 무효화됩니다.

그러나 std :: list *>를 사용하면 벡터 *는 이동할 수 있지만 벡터는 그렇지 않으므로 벡터에 대한 포인터는 유효합니다.

C++ 0x에서 이동 생성자를 추가하면 벡터 내용의 크기가 조정되지 않는 한 벡터 내용이 그대로 유지되지만 이러한 가정은 본질적으로 이식 가능하지 않습니다.

0

나는 포인터 매개 변수를 좋아한다. 그것은 스타일의 문제입니다. 이 매개 변수 유형 스타일을 선호합니다.

  • 참조 참조 : 큰 개체가 읽기 위해 전달되었습니다. 참조는 낭비되는 복사를 방지합니다. 통화 시점에서 가치별로 전달되는 것처럼 보입니다.
  • 포인터 : 개체가 을 읽고,을 쓰려면 전달 중입니다. 호출에는 포인터를 가져 오는 "&"이 있으므로 코드 검토 중에 작성이 명확 해집니다.
  • 비 const 참조 : 코드 검토에서 부작용으로 변경 될 수있는 매개 변수를 알 수 없으므로 금지되었습니다.

말한 것처럼 반복기는 부모 컨테이너 유형에 대해 무의미한 종속성을 생성합니다. (std :: list는 double-linked리스트로 구현되어 있기 때문에 그 엔트리를 삭제하면 벡터가 무효화됩니다.)

+1

const가 아닌 참조를 포인터와 비교할 때 부작용의 관점에서 차이점은 무엇입니까? 나는 다른 장소에서 다른 앰퍼샌드를 언급하는 것 외에 어떤 것도 보지 못한다. – pmr

+0

비 const 참조는 함수가 호출 될 때 값에 의한 패스와 똑같은 것처럼 보이지만 함수가 매개 변수를 변경할 수 있습니다. 즉, 코드를 읽는 사람은 함수가 무엇을 바꿀 지 알기 위해 모든 함수에 대한 모든 문서를 읽어야합니다. 필자가 설명한 스타일을 사용하면 호출을 읽고 앰퍼샌드가없는 매개 변수가 변경되지 않을 수도 있고 가능성이있는 매개 변수가 변경되지 않는다는 것을 알 수 있습니다. 이것은 대형 소프트웨어의 공식 코드 리뷰에 도움이 될 수 있습니다. –

+1

함수에 대한 문서를 읽지 않았다면 호출하지 말아야합니다. 편집 : 그리고 지옥으로 그것을 검토해서는 안됩니다. –