전체 객체 또는 컨테이너에 객체에 대한 포인터를 저장해야합니까?
처음부터 새로운 시스템을 설계합니다. STL을 사용하여 특정 장기 객체의 목록과 맵을 저장합니다.
질문 : 객체에 복사 생성자가 있는지 확인하고 STL 컨테이너 내에 객체의 사본을 저장해야합니까, 아니면 일반적으로 수명 및 범위를 직접 관리하고 해당 객체에 대한 포인터를 STL 컨테이너에 저장하는 것이 더 낫습니까?
나는 이것이 세부 사항에 대해서는 다소 짧다는 것을 알고 있지만 이것이 존재한다면 "이론적"더 나은 대답을 찾고 있습니다.
포인터를 가지고 노는 것에 대한 두 가지 명백한 단점 : 1) STL 이외의 범위에서 이러한 객체의 할당 / 할당 취소를 직접 관리해야합니다. 2) 스택에 임시 객체를 만들어 컨테이너에 추가 할 수 없습니다.
내가 놓친 다른 것이 있습니까?
사람들이 포인터를 사용하는 효율성에 주목하고 있기 때문입니다.
std :: vector의 사용을 고려하고 있고 업데이트가 적고 컬렉션을 반복하는 경우가 많고 다형성이 아닌 유형의 객체 인 경우 "복사본"개체는 더 효율적으로 참조 할 수 있기 때문에 더 효율적입니다.
Otoh, 업데이트가 공통적 인 경우 포인터를 저장하면 복사 / 이동 비용이 절약됩니다.
이것은 실제로 상황에 따라 다릅니다.
객체가 작고 객체의 사본을 작성하는 것이 가벼운 경우, stl 컨테이너에 데이터를 저장하는 것이 간단하고 평생 관리에 대해 걱정할 필요가 없기 때문에 내 의견으로는 관리하기가 더 쉽습니다.
객체가 크고 기본 생성자가 의미가 없거나 객체의 사본이 비싸면 포인터로 저장하는 것이 좋습니다.
객체에 대한 포인터를 사용하기로 결정한 경우 Boost Pointer Container Library를 살펴보십시오 . 이 부스트 라이브러리는 동적으로 할당 된 객체와 함께 사용할 수 있도록 모든 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 알고리즘과 작동하므로 매우 편리합니다.
컨테이너의 포인터 소유권을 호출자에게 전달하는 기능도 있습니다 (대부분의 컨테이너에서 해제 기능을 통해).
polymporhic 객체를 저장하는 경우 항상 기본 클래스 포인터 컬렉션을 사용해야합니다.
즉, 컬렉션에 다른 파생 형식을 저장하려는 경우 포인터를 저장하거나 슬라이싱 데몬에서 먹어야합니다.
행사 후 3 년 만에 점프해서 죄송하지만 여기에주의 할 점은 ...
마지막 큰 프로젝트에서 중앙 데이터 구조는 매우 간단한 개체 집합이었습니다. 프로젝트가 시작된 지 약 1 년이지나면서 요구 사항이 발전함에 따라 객체가 실제로 다형성이어야한다는 것을 깨달았습니다. 데이터 구조를 기본 클래스 포인터 세트로 수정하고 객체 저장, 캐스팅 등의 모든 부수적 손상을 처리하는 데 몇 주 동안 어렵고 불쾌한 뇌 수술이 필요했습니다. 새로운 코드가 작동하고 있음을 확신하기까지 몇 달이 걸렸습니다. 덧붙여서, 이것은 잘 설계된 C ++의 객체 모델이 얼마나 어려운지에 대해 생각하게 만들었습니다.
현재 대규모 프로젝트에서 중앙 데이터 구조는 매우 간단한 개체 집합입니다. 프로젝트가 시작된 지 약 1 년 (오늘날 발생), 나는 그 물체가 실제로 다형성이어야한다는 것을 깨달았습니다. 인터넷으로 돌아가서이 스레드를 찾았으며 Boost 포인터 컨테이너 라이브러리에 대한 Nick의 링크를 찾았습니다. 이것이 바로 모든 것을 고치기 위해 지난 번에 써야했던 것이므로 이번에는 둘러 보겠습니다.
어쨌든, 도덕적으로, 당신의 스펙이 100 % 돌로 던져지지 않았다면, 포인터를 찾으면 나중에 많은 작업을 저축 할 수도 있습니다.
두 세계의 장점을 모두 활용 해보십시오. 스마트 포인터 컨테이너 (예 : boost::shared_ptr
또는 std::shared_ptr
)를 사용하십시오. 메모리를 관리 할 필요가 없으며 대용량 복사 작업을 처리 할 필요가 없습니다.
일반적으로 STL 컨테이너에 객체를 직접 저장하는 것이 가장 간단하고 효율적이며 객체를 사용하는 것이 가장 쉽기 때문에 가장 좋습니다.
객체 자체에 복사 할 수없는 구문이 있거나 추상 기본 유형 인 경우 포인터를 저장해야합니다 (가장 쉬운 것은 shared_ptr을 사용하는 것입니다)
당신은 그 차이를 잘 이해하고있는 것 같습니다. 물체가 작고 복사하기 쉬운 경우에는 반드시 보관하십시오.
그렇지 않다면 힙에 할당 한 스마트 포인터 (auto_ptr, 참조 카운트 스마트 포인터 아님)를 저장하는 것에 대해 생각할 것입니다. 분명히, 스마트 포인터를 선택하면 (임시대로) 임시 스택 할당 객체를 저장할 수 없습니다.
@ Torbjörn 은 슬라이싱에 대해 좋은 지적을합니다.
컨테이너가 전체 객체 대신 포인터를 복사하기 때문에 포인터를 사용하는 것이 더 효율적입니다.
There's some useful information here about STL containers and smart pointers:
Why is it wrong to use std::auto_ptr<> with standard containers?
If the objects are to be referred to elsewhere in the code, store in a vector of boost::shared_ptr. This ensures that pointers to the object will remain valid if you resize the vector.
Ie:
std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized
If noone else stores pointers to the objects, or the list doesn't grow and shrink, just store as plain-old objects:
std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol
This question has been bugging me for a while.
I lean to storing pointers, but I have some additional requirements (SWIG lua wrappers) that might not apply to you.
The most important point in this post is to test it yourself, using your objects
I did this today to test the speed of calling a member function on a collection of 10 million objects, 500 times.
The function updates x and y based on xdir and ydir (all float member variables).
I used a std::list to hold both types of objects, and I found that storing the object in the list is slightly faster than using a pointer. On the other hand, the performance was very close, so it comes down to how they will be used in your application.
For reference, with -O3 on my hardware the pointers took 41 seconds to complete and the raw objects took 30 seconds to complete.
'IT' 카테고리의 다른 글
Linux의 C ++ 동적 공유 라이브러리 (0) | 2020.06.02 |
---|---|
언제 WeakHashMap 또는 WeakReference를 사용 하시겠습니까? (0) | 2020.06.02 |
안드로이드가 프로세스를 죽이는 것을 시뮬레이션하는 방법 (0) | 2020.06.02 |
변수에 표준 오류를 저장하는 방법 (0) | 2020.06.02 |
C # 또는 VB.NET에서 할 수없는 MSIL에서 무엇을 할 수 있습니까? (0) | 2020.06.02 |