2010-06-17 3 views
4

STL 벡터 클래스는 push_back을 호출 할 때마다 복사 생성자를 사용하여 개체의 복사본을 저장합니다. 프로그램을 느리게하지 않겠습니까? 개체에 대한 포인터를 처리하는 클래스의 사용자 지정 연결된 목록 종류를 가질 수 있습니다. 그것은 STL의 몇 가지 이점을 가지지는 못하지만 더 빨라야합니다. 출력도 그 값을 검색 할 때 추가 할 때 복사 생성자 두 번 호출 보여줍니다STL 벡터 성능

adding first...copy 
adding second...copy 
copy 

:

#include <vector> 
#include <iostream> 
#include <cstring> 

using namespace std; 

class myclass 
{ 
    public: 
     char* text; 

     myclass(const char* val) 
     { 
      text = new char[10]; 
      strcpy(text, val); 
     } 

     myclass(const myclass& v) 
     { 
      cout << "copy\n"; 
      //copy data 
     } 
}; 

int main() 
{ 
    vector<myclass> list; 
    myclass m1("first"); 
    myclass m2("second"); 

    cout << "adding first..."; 
    list.push_back(m1); 

    cout << "adding second..."; 
    list.push_back(m2); 

    cout << "returning..."; 
    myclass& ret1 = list.at(0); 
    cout << ret1.text << endl; 

    return 0; 
} 

출력과 같이 나온다 :

아래 코드를 참조하십시오. 큰 오브젝트가있을 때 성능에 영향을 줍니까?

+5

논쟁의 여지가있는 몇 가지 디자인 옵션이 있습니다.하지만 여기서는 그렇지 않습니다 : O (1) 삽입을위한 링크 된 목록을 원할 경우 자신의 롤을 사용하지 마십시오. - std :: 목록 '. –

+2

x가 y보다 빠르다는 것을 묻는다면, 그냥 시도해보고 측정하십시오. –

답변

10

복사하면 성능에 영향을줍니다. 대형 컨테이너를 표준 컨테이너에 보관하는 경우 오브젝트 대신 스마트 포인터를 사용하는 것이 좋습니다.

4

예. 이것은 우리가 C++ 0x에서 rvalue 참조를 얻게 될 주요 이유 중 하나입니다.

-1

먼저 벡터에서 자신의 클래스를 사용할 때 대신 포인터를 사용하는 것이 좋습니다. 그러나 여기서 데이터로 text이 포인터로 저장됩니다. 그것의 (텍스트 속성의 값) 두 번 복사되지 않습니다. 그래서이 응용 프로그램에서 주요 성능 문제가 없습니다.

+0

클래스가 크고 비용이 많이 들고 시간을 절약해야하는 경우에만. 클래스가 4 바이트 만 있다면 값으로 저장하는 것이 더 빠르고 쉽습니다. 그리고이 경우에는 포함 된 텍스트를 복사하려는 의도가 있다고 생각합니다 (완전한 복사 생성자를 제공하지 않았기 때문에 알려주지는 못하지만). – Peter

+0

그래서 일반 시나리오 대신 포인터를 사용하는 것입니다. –

+0

크기가 결정의 유일한 요소가 아니기 때문에 일반적인 시나리오에서는 스마트 포인터의 사용을 요구하지 않습니다. 원시 포인터를 사용하는 것은 권장되지 않습니다. –

0

복사는 성능에 약간의 영향을 미칩니다. 작은 물체의 경우 값으로 저장하고 프로파일 링하면 재검토해야하는지 알려줍니다. 큰 객체의 경우 컨테이너에 스마트 포인터를 저장하여 우려 사항을 완화 할 수 있습니다. 다시 말하지만 객체를 값으로 저장하는 것이 자연 스럽다면 프로파일 링이 병목 현상을 나타내는 경우가 아니라면 그렇게하십시오.

나는 반환이 실제로 사본을 만들고 있다고 생각하지 않습니다. 당신이보고있는 것은 "두 번째 추가"가 아마도 두 개의 복사본을 만드는 것입니다 : 첫째, 벡터를 1에서 (아마) 2로 확장하고 이전 위치에서 새로운 요소로 이전 요소를 복사 한 다음 요소 2를 복사해야합니다 그 자리에.

1

모든 것은 개체의 크기에 따라 달라집니다.하지만 대부분의 경우 값 의미 (전체 개체 복사)를 사용하는 것이 좋으며 성능이 충분히 높아야합니다. 그것은 포인터와 관련된 메모리 관리에 관해 생각할 필요가 없게합니다.

성능이 충분하지 않은 경우에만 포인터를 사용하고 메모리 관리를주의 ​​깊게 고려해야합니다.

포인터가 필요하면 자신의 컬렉션 클래스를 배포하는 대신 vector<myclass*>을 사용하십시오. 그것은 STL의 아름다움입니다 generic =)

+2

그래서 스마트 포인터가 존재하는 이유입니다. 이러한 모든 위험을 피하기 위해서입니다. – ereOn

+1

예, 대단히 도움이됩니다. 내가 말하고자하는 것은 가치 의미보다 포인터 의미론을 사용하는 것을지지하지 않는다는 것입니다. 이유는 성능과 관련된 모든 시간에 말입니다. 스마트 포인터를 사용하면 여전히 값에 비해 뇌의 오버 헤드가 상대적으로 많습니다. 포인터는 성능상의 이점이 있지만 공유 데이터를 의미하기도합니다. 동시성. 저는 KISS (Keep It Sweet & Simple)를 믿습니다. 조숙 한 최적화는 모든 악의 뿌리입니다.) – ryaner

+0

"대부분의 경우 값 의미 (전체 객체 복사)를 사용하는 것이 더 낫습니다." 병사. 기억은 제쳐두고 여전히 나쁜 생각입니다. –

3

기본 유형을 저장하지 않는 한, 실제 객체 자체 대신 벡터 요소로 포인터를 사용하는 것이 좋습니다. 그리고 많은 경우 스마트 포인터를 사용하는 것이 좋습니다.
ctor는 여전히 호출되지만 클래스의 클래스 포인터가 아니라 스마트 포인터 클래스입니다.

5

다른 포스터에서 언급하지 않은 것 중 하나는 벡터에 필요한 요소의 수를 알고있는 경우 vector :: reserve를 사용하여 벡터의 메모리 영역을 미리 할당 할 수 있다는 것입니다. 이것은 벡터 클래스가 루프 내의 용량 제한에 관계없이 새로운 인접한 메모리 블록을 계속 재 할당 할 필요가 없기 때문에 push_back을 사용하여 객체를 값으로 저장하는 경우 특히 속도가 빨라집니다.

1

당신은 그것을 믿을 수 있지만 vector (더 나은 여전히 ​​deque)는 STL은 대부분의 작업을 위해 제공하는 가장 빠른 컨테이너입니다.

개체를 복사하는 것에 대해 걱정할 수도 있지만 매우 크거나 복사 생성자가 다소 복잡한 경우가 아니라면 힙에 할당 한 개체를 복사하는 것이 비용이 적게 듭니다.

힙 할당과 결과 캐시 누락은 단순한 복사보다 훨씬 더 큰 벌점입니다.

유휴 상태에서 장난을 치지 마십시오. vector에 대한 벤치 마크를 벤치마킹하고 어떤 것이 위에 오는지, 어떤 순서로 볼 지, 나는 놀랐을 것입니다.

그리고 정말 클래스가 복사 거대한 또는 금지하는 경우, 당신은 당신은 분명 창에 의해 캐시 지역을 던지고있는 풀을 사용하지 않는하지만, 항상 boost::ptr_vector가)

0

복사 객체는 예상치 못한 사이 드를 가질 수 있습니다 효과. 현실은 C++ 수업이 종종 복사되지 않기 때문에 오류가 발생할 수 있습니다 ... 이상 주의자는 "수업을 올바르게 작성해야합니다"라고 주장하지만 실제로 다루기를 선호합니다. 일어난다. 클래스 생성/삭제에 대한 로깅은 말할 것도없고 많은 일이 발생할 것입니다.

기본적으로 코더 의 의미는입니다. 사본이 작성되었습니다. 이것만으로도 사소한 유형에 대한 나쁜 계획이라는 의미입니다. 간단한 경우 Point2D 클래스를 사용하는 것이 좋지만 클래스가 소량의 데이터를 전달하지 않는 경우 포인터를 저장하거나 스마트 포인터를 사용하는 것이 일반적이므로주의해야합니다.

0

사용 사례에 가장 적합한 성능 특성을 가진 컨테이너를 선택해야합니다. 컨테이너 뒷면에 항목을 추가해야하는 것처럼 사용 사례가 나타납니다. vector을 사용하면 최대 회원 수를 미리 알지 못하고 다시 reserve을 가질 수있는 경우가 아니면 때때로 재 할당 및 실적 조회가 발생합니다.

대신 deque을 사용하면 무작위 액세스와 같은 유용한 기능을 유지하면서 컨테이너의 뒷면 (또는 정면)에 일정 시간 삽입이 보장됩니다.

의미 상으로 객체의 컨테이너를 포인터의 벡터로 변경하면 성능상의 이유로 포인터를 사용하지 않는 것이 좋습니다. 실제로 모든 객체가 개별 메모리 할당을 필요로하기 때문에 성능이 좋지 않을 수 있습니다. 여러 객체에 대한 메모리가 미리 할당 될 수있는 객체의 컨테이너.