2012-05-14 5 views
3

C++에서 다른 방법으로 안전하게 할당 된 것에 대한 포인터입니까?벌거 벗은 포인터는 얼마나 나쁜가?

지금까지 모든 동적 메모리 요구에 STL 컨테이너 (한 가지 경우에는 배열이지만 다른 질문)를 사용하여 명시 적으로 new 키워드를 사용할 필요가 없었습니다. 나는 또한 blithely 일반 ol 'int *foo 포인터를 참조하는 것들을 사용했습니다. 이제는 스마트 포인터에 대해 읽었습니다. (자바에 대해서는 잘랐습니다. 이전에는 이것에 대해 걱정할 필요가 없었습니다.) 일반적인 지혜는 "맨손으로 나쁘다. 사용하지 마세요."라고되어 있습니다.

얼마나 많은 문제가 있습니까? 그들이 가리키는 것들이 다른 파괴 조건을 가지고있는 한, 안전하게 포인터를 계속 사용할 수 있습니까? 내가 도망 갈 수있는 것이지만 앞으로는 피해야합니까? 아니면 제작에 재앙이되어 서둘러 수정해야합니까?

+0

예외 안전 RAII를 읽고 C++ 11의 새로운 스마트 포인터 중 두 가지를보아야합니다 (부스트가 잠시 동안있었습니다) :'std :: shared_ptr '및'std :: shared_ptr unique_ptr '. 그리고 비슷한 질문이 많이 있습니다 : http://stackoverflow.com/questions/6675651/when-should-i-use-c-pointers-over-smart-pointers. 특히, 예외 안전성은 예외가 발생하고 스택이 해제 될 때 메모리 누수와 같은 관련 문제를 방지하고 배워야하는 주목할만한 특징이 있습니다. – birryree

답변

6

벌거 벗은 포인터는 본질적으로 안전합니다. 위험한 그릇된 사용법입니다 (쉽게 옮길 수 있습니다). 스마트 포인터는 멋지지만 모든 것이 있지만 일부 (shared_ptr)에는 참조 횟수가 포함되어 성능 저하가 발생합니다. 해당되는 경우 스마트 포인터를 사용하려고 시도해야하지만 포인터를 사용하는 AFAIK는 끔찍한 실수로 간주되지 않습니다.

STL 컨테이너의 구성원을 참조 할 때 주소가 변경되어 재배치 중에 이상한 버그가 남을 수 있으므로주의해야합니다.

+2

[unique_ptr] (http : // en .cppreference.com/w/cpp/memory/unique_ptr) 및 [scoped_ptr] (http://www.boost.org/doc/libs/1_49_0/libs/smart_ptr/scoped_ptr.htm)은 성능 오버 헤드가 없으며 필요합니다 예외 상황에서 메모리 누수가 발생하지 않도록하십시오. –

+0

명확하게 답변을 편집했습니다. – Tibor

+0

Re : 답안의 마지막 문장 - Daaaang. 그것은 거의 확실하게 달려 들었지만 내 스스로 알아 내지 못했던 것 같습니다. –

1

코드를 작성하고 유지 관리하는 사람들의 완벽한 세상에서 실수를하지 않아도 원시 포인터는 놀랍습니다.

불행히도, 그렇지 않습니다. 무엇보다도 맨손 포인터는 에러가 발생하기 쉽고, 포인터가 알지 못해 무효화 될 수있는 메모리를 가리키며, 포인터는 별명을 지정할 수 있으며 포인터는 내용을 변경합니다.

"어리 석음"을 보충하기 위해 실제로 스마트 포인터가 필요합니다. 적어도 뭔가는 "스마트"해야합니다 :).

매우 열악한 것에 대해 작업하지 않는 한, 원시 포인터를 사용하지 않아도됩니다. 왜냐하면 단순히 "너무 똑똑하지 않기"때문입니다. 즉, 매우 조심스럽고 코드를 작성한 후에 코드를 사용하는 사람들은 매우 신중한 경우가 많습니다 (그다지 그렇지 않은 경우보다 더 자주 발생합니다). 그런 다음 원시 포인터를 사용하지만 그 외에도 스마트를 사용하십시오 포인터는 거의 또는 전혀 오버 헤드가 발생하지 않습니다.

unique_ptr<>은 이동시킬 때까지 오버 헤드가 전혀 없으며,이 경우 하나의 NULL을 메모리에 씁니다. 현대 컴파일러에서는 이것이 자주 최적화됩니다.

shared_ptr<>은 멀티 스레드 응용 프로그램에서 사용되는 경우 특히 상당한 오버 헤드가 발생할 수 있습니다. 그러나이 방법이 유용 할 수 있으므로 큰 문제는 아닙니다.

전체적으로 원시 포인터를 고칠 필요는 없지만 사용법은 권장하지 않습니다.

+0

'완벽한'세계 시나리오에 동의하지 않을 것입니다. 원시 포인터는 RAII를 따르지 않으며 본질적으로 예외 안전하지 않습니다. 완벽한 세상에서 사람들은 그것들을 사용할 것입니다 – 111111

+1

누드 포인터는 소유하지 않은 리소스를 가리키는 데 유용하기 때문에 upvote가 없습니다. (글쎄, 당신은'boost :: optional '을 쓸 수 있었지만, 왜 그렇게 했습니까?) –

+0

자신이 소유하지 않은 것들을 가리키면 때때로 재미있는 시간을 가져올 수 있습니다.) – ScarletAmaranth

1

"맨손의 포인터가 좋지 않아 사용하지 마십시오."작은 부록과 함께 "정리해야 할 항목을 지적하십시오."라는 말이 완전히 정확합니다.

개체가 있고 그 개체를 파괴하는 것이 다른 사람의 책임이면 원시 포인터는 절대적으로 좋습니다. 그러나, 당신이 어떤 정리 기능을 통해 객체를 파괴 할 책임이있는 순간, 항상 스마트 포인터를 사용하십시오.또한, 당신은 청소하지 않는 객체에 대해, vector 크기를 조절, 그들은 다른 시스템 - 기능 지역 주민에 의해 정리됩니다 어떤 조건 아래에서의 인식 소유 등

규칙 :

  • 소유권 : T*, 당신은 더 이상
  • 공유 소유권 사용할 수 없습니다 때의주의 : shared_ptr<T>
  • 고유 소유권 필요한 경우 사용자 정의 Deleter가 사용 unique_ptr<T, Del>, 필요한 경우 사용자 정의 Deleter가를

항상 이러한 규칙을 따르므로 메모리 누수, 이중 해제, 잘못된 포인터 액세스 또는 유사한 메모리 관련 버그가 발생하지 않습니다.

+0

분명히 규칙보다 조금 더 있습니다! (이름이없는'shared_ptr' 임시 변수를 통해 누출되는) (http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#BestPractices) 또는 ['shared_ptr' cycles] (http : /www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#Introduction) 한 쌍의 이름을 지정하십시오. – Fraser

-2

newdelete을 너무 걱정하지 않아도 불량 포인터가 잘못되었습니다. 이 동작으로 인해 매우 이상한 오류가 발생할 수 있습니다. 내가 제안하는 것은 메모리 누수 검사기 Valgrind을 사용하는 방법을 배우기 위해 힙에 할당 된 두 개의 포인터와 객체로 작업해야 할 때입니다.

new []와 배열을 실체화 할 때 다음 몇 가지 간단한 규칙, 당신은 항상 delete []으로 삭제해야하고 new와 함께 하나의 객체를 실체화 할 때 반대로 다음 항상 delete를 호출합니다.

new 혼합 방지하기 위해 기억 -이 할 예 결코을 위해 그 기능이 서로 함께 작동하도록 설계되지 않기 때문에 delete[] - free 또는 new[]와 -와 deletemalloc :

int *a = (int*)malloc(10*sizeof(int)); 
delete a; 

하지만

int *a = new int[10]; 
delete[] a; 

Tibor는 포인터의 사용 자체가 나쁘지는 않지만 항상 그렇듯이 "With 중대한 힘은 중대한 책임 "온다 : P

+0

'new []'로 아무 것도 인스턴스화하지 말고 절대로 직접 파괴 함수를 호출하지 마십시오. – Puppy

+0

왜 downvote? 나는 스마트 포인터 사용에 동의하지만 이것들은 "베어 포인터"사용자에게 유용한 힌트 일뿐입니다. – linello

+2

나는 downvote하지 않았지만 스마트 포인터는 예외 안전 코드에 필요하다. 'new'와'delete' 사이의 함수가 예외를 던지면 프로그램은 절대로'delete'를 호출하지 않고 메모리를 누설합니다. –

0

벌거 벗은 포인터는 말썽으로 얻기 쉽기 때문에 나쁘게 여겨진다. 스마트 포인터는 자동으로 문제를 처리하기 때문에 오류가 발생하지 않습니다.

모든 코드를 절대적으로 제어 할 수있는 경우 (즉, 프로젝트의 유일한 코더 인 경우) 기본 메모리 할당 법과 관습을 따르는 한 베어 포인터를 사용하는 것이 좋습니다. "누구든지 메모리를 할당합니다. 다르게 명시된 경우를 제외하고는 그것을 제거합니다. "). 그러나 코드 (예 : 1 개 이상의 코더가있는 프로젝트)로 다른 사람들과 작업 할 때 실수와 오해의 문을 엽니 다.

스마트 포인터는 누가 개체를 소유하고 있는지 (따라서 누가 그것을 할당해야하는지)를 관리합니다. 또한 해당 개체를 사용하는 마지막 코드가 더 이상 필요 없게 된 시점을 추적 할 수 있으므로 할당 된 데이터를 공유 할 때 안전하게 할당을 해제 할 수 있습니다.

카운트를 참조하는 스마트 포인터는 힙에서 메모리를 할당하는 클래스의 데이터 멤버에 대한 안전한 기본 복사본 생성자와 안전한 기본 복사본 할당 연산자를 생성합니다.그들은 참조 카운팅 스마트 포인터를 복사중인 원본 개체에 안전하게 설정할 수 있으며 원래 또는 복제본이 범위를 벗어나 삭제되면 스마트 포인터를 통해 관리 및 공유되는 할당 된 메모리가 여전히 그것을 가리키는 다른 객체. 맨손의 포인터에서는 그렇지 않습니다. 베어 포인터를 사용하는 경우 복사 할당 연산자와 복사 생성자를 작성하여 메모리를 할당하는 객체를 복제하여 포함 된 소유 데이터의 데이터 손상을 방지해야합니다.

+0

카운트를 참조하는 스마트 포인터는 안전한 기본 복사 생성자를 생성하지만 99 %의 시간은 원하는 작업을 수행하지 않고 이중 삭제 이외의 원시 포인터와 유사하게 작동합니다. –

관련 문제