2010-02-12 7 views
7

나는 게임을 만들고 있고 총알이 나는 벡터를 가지고있다. 총알이 끝나면 나는 총알을 낸다. 총알 .begin() + i); 그런 다음 총알이 사라집니다. 그러나 그것은 기억의 막대를 얻는 것을 생각하지 않습니다. 5,000 개의 탄환을 작성한 후 5,000 개를 더 만들면 메모리는 그대로 유지되지만 5,000 개가 더 비행하는 동안 5,000 개를 만들면 새로운 공간이 할당됩니다. 실제로이 메모리를 비우려면 어떻게해야합니까?적절한 벡터 메모리 관리

감사 벡터의 메모리 할당 모델은 기본적으로는 그렇지 않은 있도록 새로운 요소 삭제 된 부분을 채우기 위해 할 수 있습니다 추측하려고 상각 일정 시간 push_back 작업을 제공하기 위해 동작하는 방식을 일반적입니다

+0

어떻게 지내니? STL, Boost, roll-your-own, 또는 다른 것? – John

+0

STL 벡터는 하나입니다 – jmasterx

+0

크기를 줄이기 위해'std :: vector :: resize()'를 사용할 수 있습니다. http://www.cplusplus.com/reference/stl/vector/resize –

답변

14

std::vector 클래스는 내부 메모리를 자동으로 관리합니다. 그것은 당신이 넣은만큼 많은 아이템을 보유 할 수있게 확장되지만, 일반적으로 아이템을 제거 할 때 자체적으로 축소되지는 않습니다 (물론 파괴 될 때 메모리를 해제 할지라도).

std::vector에는 "크기"라는 두 가지 관련 개념이 있습니다. 첫 번째는 예약 된 크기로, 벡터 요소를 저장하기 위해 시스템에서 할당 한 메모리 양입니다. 두 번째는 "used"크기이며, 이는 얼마나 많은 요소가 논리적으로 벡터에 있는지를 나타냅니다. 분명히 예약 된 크기는 적어도 사용 된 크기만큼 커야합니다. size() 방법으로 사용 된 크기를 알아낼 수 있으며 (이미 알고있는 것으로 알고 있습니다) capacity() 방법을 사용하여 예약 크기를 찾을 수 있습니다.

일반적으로 사용 된 크기와 예약 된 크기가 같고 새 요소를 삽입하려고하면 벡터는 이전 예약 크기의 두 배가되는 새 내부 버퍼를 할당하고 기존 요소를 모두 해당 버퍼에 복사합니다 . 이것은 당신이 가지고있는 반복자를 무효화한다는 점을 제외하고는 여러분에게 투명합니다. 이전에 AFAIK에서 언급했듯이 대부분의 STL 구현은 삭제 된 것에 대한 응답으로 예약 된 크기를 축소하지 않습니다. 당신이 증가reserve() 방법을 사용하여 예약 된 크기로 벡터를 강제 할 수있는 동안

불행하게도,이 예약 용량을 감소 작동하지 않습니다. 지금까지 내가 말할 수있는 용량의 감소를 초래에 대한 가장 좋은 방법은 다음을 수행하는 것입니다

std::vector<Bullet>(myVector).swap(myVector); 

를 이것이하지만와 (원래 벡터의 카피 인 임시 벡터를 만들 수있다 할 것입니다 최소 필요 용량), 두 벡터의 내부 버퍼를 교체하십시오.이렇게하면 원본 벡터의 데이터는 같지만 예약 크기가 작아집니다.

이제 임시 사본을 만드는 작업이 비교적 비용이 많이 들기 때문에 (정상적인 읽기/삽입/삭제보다 훨씬 많은 프로세서 시간이 소요됨) 요소를 지울 때마다 수행하지 않으려 고합니다. 같은 이유로, 벡터가 기존 크기를 초과해야 할 때 벡터를 1 씩 늘리지 않고 예약 된 크기를 두 배로 늘리는 이유입니다. 따라서 내가 추천하는 것은 상대적으로 많은 수의 요소를 지우고 곧 더 많은 요소를 추가하지 않을 것이라는 것을 알고 있다면 위의 스왑 트릭을 수행하여 용량을 줄이는 것입니다.

마지막으로 std::vector 이외의 것을 사용하는 것도 좋습니다. 자주 사용하는 것처럼 보이는 벡터 중간에서 요소를 지우는 것은 많은 다른 유형의 데이터 구조와 비교할 때 느린 작업입니다 (벡터는 이후 모든 요소를 ​​구멍을 채우기 위해 한 슬롯 뒤로 복사해야하기 때문에) . 어떤 데이터 구조가 목적에 가장 적합한지는 데이터로 무엇을하고 있는지에 따라 다릅니다.

+0

+1이 비싼 가운데에서 지우기에 대한 포인트뿐만 아니라,이 답변의 포괄 성. –

+1

스왑은 참조에 의해 인수를 취하고 생성자 호출은 rvalue이므로'myVector.swap (std :: vector (myVector)); '는 유효하지 않습니다. 코드를 준수하도록 매개 변수를 전환하십시오.'std :: vector (myVector) .swap (myVector); ' – fredoverflow

+0

@Fred 감사합니다. 나는 다른 방법으로 그것을 썼다. 왜냐하면 그런 식으로 진행되는 것을 따라하기가 더 쉬워 보이기 때문이다. 그러나주의해야한다는 것을 잊어 버렸다. 결정된. –

2

기억을 풀어 라. 이렇게하면 상수 할당 및 할당 취소를 피할 수 있습니다. 이 문제를 해결하려면 스왑 트릭을 사용하여 사용되지 않는 벡터 메모리를 비울 수 있습니다. 빈 벡터를 임시 이름없는 벡터로 바꿔서 임시 벡터가 범위를 벗어날 때 소멸자에서 메모리를 해제하도록하려면 다음과 같이하십시오. vector<int>(c).swap(c)

+0

조금 익숙하지 않다. – jmasterx

+0

잘 알려진 해킹이다. 의도적으로 벡터는 자체적으로 축소되지 않습니다. –

+0

내가 원하는 것을 할 수있는 stl이 있습니까? – jmasterx

3

먼저 std :: vector erase 메서드는 그리 효율적이지 않습니다. 삭제 된 항목 이후에 모든 항목을 이동해야합니다. 벡터 항목 (글 머리 기호)의 순서가 중요하지 않은 경우 삭제 된 글 머리표를 마지막 글 머리표로 바꾸고 마지막 글 머리표를 삭제하는 것이 빨라집니다 (선형 복잡성 대신 일정한 복잡성을 얻음).

둘째, 실제 문제는 무엇입니까? 10,000 개의 항목을 삭제 한 후 메모리가 해제되지 않았습니까? 운영 체제에서보고 한 여유 메모리 또는 힙의 여유 공간에 대해 이야기하고 있습니까? 가능한 다른 객체가 벡터의 데이터 위치 뒤에 할당 되었기 때문에이 메모리를 운영 체제로 비우는 것은 불가능합니다. 그러나 새로 생성 된 다른 객체에 대해서는 재사용 할 수 있습니다.

2

나는이 두 숙어를 살펴보고 당신에게 가장 맞는 하나를 선택하는 것이 좋습니다 : 그것은 메모리를 제거하지 않을 수 있습니다
Shrink to fit
Clear & minimize

+1

+1 관용구에 이름을 올리면 암기하고 의사 소통하기가 더 쉽습니다. –

+0

감사합니다.이 책은 황금입니다 :) –

1

.
그러나 다음에 황소를 추가해야 할 경우 더 많은 공간을 다시 할당 할 필요가 없습니다.
지운 총알이 나온 메모리를 다시 사용하지 않습니다.

참고 :
컨테이너 중간에서 자주 지우는 경우 벡터가 올바른 컨테이너가 아닐 수 있습니다. 이것은 요소 n을 제거한 다음 [n + 1, end]의 모든 요소를 ​​메모리의 한 공간 아래로 이동해야하기 때문입니다.

0

총알이 끝나면 bullets.erase (bullets.begin() + i);

하지 마십시오. 프레임 당 여러 개의 글 머리 기호가 끝나면 완료되지 않은 글 머리 기호가 반복해서 복사되기 때문에 무서운 성능을 얻습니다. 실제로는 필요하지 않습니다. 내가하는 일은 다음과 같습니다.

#include <algorithm> 
#include <functional> 
#include <vector> 

class Bullet 
{ 
    // ... 
public: 
    bool is_finished() const; 
}; 

int main() 
{ 
    std::vector<Bullet> bullets; 
    // ... 
    bullets.erase(
     std::remove_if(
      bullets.begin(), 
      bullets.end(), 
      std::mem_fun_ref(&Bullet::is_finished) 
     ), 
     bullets.end() 
    ); 
} 

이 방법은 각 라이브 글 머리 기호를 최대 한 번만 이동시킵니다.