전체 객체를 저장하거나 컨테이너의 물체에 포인터를 저장해야합니까?

StackOverflow https://stackoverflow.com/questions/141337

  •  02-07-2019
  •  | 
  •  

문제

새로운 시스템을 처음부터 설계합니다. STL을 사용하여 특정 장기적인 객체의 목록과지도를 저장합니다.

질문 : 내 객체에 사본 생성자와 STL 컨테이너 내에 객체의 사본을 보관 해야하는지 확인해야합니까, 아니면 일반적으로 수명 및 범위를 직접 관리하고 STL 컨테이너에 해당 객체에 포인터를 저장하는 것이 일반적으로 더 좋습니다.

나는 이것이 세부 사항이 다소 짧다는 것을 알고 있지만,이 두 솔루션이 모두 가능하다는 것을 알고 있기 때문에 "이론적"더 나은 대답을 찾고 있습니다.

포인터를 가지고 노는 것에 대한 두 가지 명백한 단점 : 1) STL 이외의 범위에서 이러한 객체의 할당/거래를 관리해야합니다. 2) 스택에 온도 객체를 생성하고 컨테이너에 추가 할 수 없습니다.

내가 놓친 것이 있습니까?

도움이 되었습니까?

해결책

사람들은 포인터를 사용하는 효능에 갇히고 있기 때문에.

STD :: 벡터를 사용하는 것을 고려하고 업데이트가 적고 컬렉션을 종종 반복하면 객체를 저장하는 비 다형성 유형 저장 객체 "사본"이 더 나은 참조를 얻을 수 있으므로 더 효율적입니다.

OTOH, 업데이트가 일반적인 저장 포인터 인 경우 사본/재배치 비용이 절약됩니다.

다른 팁

이것은 실제로 당신의 상황에 달려 있습니다.

객체가 작고 객체 사본을 수행하는 것이 가벼운 경우, STL 컨테이너 내에 데이터를 저장하는 것은 평생 관리에 대해 걱정할 필요가 없기 때문에 내 의견으로는 간단하고 관리하기 쉽습니다.

객체가 크고 기본 생성자가있는 경우 의미가 없거나 물체 사본이 비싸면 포인터와 함께 저장하는 것이 좋습니다.

객체에 포인터를 사용하기로 결정한 경우 포인터 컨테이너 라이브러리 부스트. 이 부스트 라이브러리는 동적으로 할당 된 객체와 함께 사용하기 위해 모든 STL 컨테이너를 감싸고 있습니다.

각 포인터 컨테이너 (예 : ptr_vector)는 컨테이너에 추가 될 때 객체의 소유권을 취하고 해당 객체의 수명을 관리합니다. 또한 참조로 PTR_ 컨테이너의 모든 요소에 액세스합니다. 이것은 당신이 같은 일을 할 수 있습니다

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

이 클래스는 STL 컨테이너를 감싸고 모든 STL 알고리즘과 함께 작동합니다.

컨테이너의 포인터 소유권을 발신자에게 전송하기위한 시설도 있습니다 (대부분의 컨테이너의 릴리스 기능을 통해).

폴리 포르 미어 객체를 저장하는 경우 항상 기본 클래스 포인터 모음을 사용해야합니다.

즉, 컬렉션에 다른 파생 유형을 저장할 계획이라면 포인터를 저장하거나 슬라이싱 데몬이 먹어야합니다.

행사 후 3 년 만에 뛰어 들어 죄송하지만 여기에주의 사항이 있습니다 ...

마지막 큰 프로젝트에서 내 중앙 데이터 구조는 상당히 간단한 객체 세트였습니다. 프로젝트에 약 1 년 동안 요구 사항이 발전함에 따라 나는 물체가 실제로 다형성이어야한다는 것을 깨달았습니다. 데이터 구조를 기본 클래스 포인터 세트로 고정하고 객체 저장, 캐스팅 등의 모든 담보 손상을 처리하는 데 몇 주 동안 어려움과 불쾌한 뇌 수술이 필요했습니다. 새 코드가 작동하고 있음을 스스로 설득하는 데 몇 달이 걸렸습니다. 덧붙여서, 이것은 C ++의 객체 모델이 얼마나 잘 설계된지에 대해 열심히 생각하게 만들었습니다.

현재 큰 프로젝트에서 내 중앙 데이터 구조는 상당히 간단한 객체 세트입니다. 프로젝트에 약 1 년이 걸렸을 때 (오늘이 일이 발생), 나는 실제로 대상이 다형성이어야한다는 것을 깨달았습니다. 그물로 돌아가서이 스레드를 발견하고 Nick의 Boost Pointer 컨테이너 라이브러리에 대한 링크를 발견했습니다. 이것이 바로 모든 것을 고치기 위해 지난번에 써야했던 것입니다. 그래서 나는 이번에 그것을 갈 것입니다.

어쨌든 도덕은 나에게 : 당신의 사양이 돌로 100% 캐스팅되지 않으면 포인터를 찾아 가면 나중에 많은 일을 구할 수 있습니다.

두 세계를 최대한 활용하지 않겠습니까? 스마트 포인터 컨테이너 (예 : boost::shared_ptr 또는 std::shared_ptr). 메모리를 관리 할 필요가 없으며 대규모 복사 작업을 처리 할 필요가 없습니다.

일반적으로 물체를 STL 컨테이너에 직접 저장하는 것은 가장 단순하고 효율적이며 객체를 사용하는 데 가장 쉽습니다.

객체 자체가 인사가 불가능한 구문이 있거나 추상적 인 기본 유형 인 경우 포인터를 저장해야합니다 (가장 쉬운 shared_ptr를 사용하는 것이 가장 쉬운 것입니다).

당신은 차이를 잘 이해하는 것 같습니다. 객체가 작고 복사하기 쉬운 경우 반드시 저장하십시오.

그렇지 않다면, 나는 당신이 힙에 할당하는 사람들에게 스마트 포인터 (auto_ptr, 심판 카운트 스마트 포인터)를 저장하는 것에 대해 생각합니다. 분명히, 당신이 스마트 포인터를 선택한다면, 당신은 당신이 말한대로 온도 스택 할당 된 객체를 저장할 수 없습니다.

@Torbjörn 슬라이스에 대해 좋은 지적을 만듭니다.

컨테이너는 전체 물체 대신 포인터 만 복사하기 때문에 포인터를 사용하는 것이 더 효율적입니다.

STL 컨테이너 및 스마트 포인터에 대한 유용한 정보가 있습니다.

표준 컨테이너와 함께 std :: auto_ptr <>를 사용하는 것이 왜 잘못입니까?

객체를 코드의 다른 곳에서 언급하는 경우 Boost :: shared_ptr의 벡터에 저장하십시오. 이렇게하면 벡터 크기를 조정하면 객체에 대한 포인터가 유효하게 유지됩니다.

즉:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

다른 사람이 객체에 포인터를 저장하지 않거나 목록이 자라거나 줄어들지 않으면 평범한 객체로 저장하십시오.

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

이 질문은 한동안 나를 괴롭 혔습니다.

나는 포인터를 저장하는 데 의지하지만, 당신에게 적용되지 않을 수있는 몇 가지 추가 요구 사항 (Swig Lua 포장지)이 있습니다.

이 게시물에서 가장 중요한 점은 다음과 같습니다 직접 테스트하십시오, 사용 당신의 대상

나는 오늘이 일을 500 번씩 1 천만 개 객체의 컬렉션에서 멤버 함수를 호출하는 속도를 테스트하기 위해이 작업을 수행했습니다.

함수는 XDIR 및 YDIR (모든 플로트 멤버 변수)을 기반으로 X와 Y를 업데이트합니다.

STD :: 목록을 사용하여 두 유형의 객체를 모두 고정했으며 목록에 객체를 저장하는 것이 포인터를 사용하는 것보다 약간 빠릅니다. 반면에 성능은 매우 가까웠으므로 응용 프로그램에서 어떻게 사용되는지에 달려 있습니다.

참조를 위해, 내 하드웨어에 -O3을 사용하면 포인터는 완료하는 데 41 초가 걸렸고 원시 물체는 완료하는 데 30 초가 걸렸습니다.

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