2010-12-08 3 views
3

this question을 실험하면서 나는 완전히 이해하지 못하는 예를 만들었습니다. 특히 포인터, 참조 및 boost :: shared_ptr에 대한 나의 오해를 강조합니다. 이 코드를 실행boost :: shared_ptr 질문. 왜이게 효과가 있니?

int& r = *(new int(0));//gratuitous pointer leak, got to initialize it to something 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    r = *sp; 
    cout << "r=" << r << endl; 
} 
cout << "r=" << r << endl << endl; 

int* p; 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    p = &*sp; 
    cout << "*p=" << *p << endl; 
} 
cout << "*p=" << *p << endl; 

이 같은 출력 뭔가를 제공합니다

r=100 
r=100 

*p=100 
*p=13 

왜 기준이있는 shared_ptr의 죽음을 생존 않습니다를하지만 포인터하지 않습니다? 여기에있는 답변에 문제가있다


두 정반대과 모순 솔루션과 진실이되는 합의가있을 것 같다. shared_ptr이 삭제 된 후 참조를 사용할 수있는 기능이 좋겠지 만 무효 한 경우이 사실을 이해해야합니다.

누군가가 참조에서 정의되지 않은 동작을 나타내는 간단한 예제를 게시 할 수 있습니다.

+0

블록 순서가 바뀌면 참조가 존속하고 포인터는 그렇지 않습니다. 그러나 이것은 단지 행운이라는 말을하는 거지? – JnBrymn

+0

내 의견이 잘못되었습니다. @ FredOverflow의 대답을 참조하십시오. 죄송합니다 ... –

+0

'* (new ...)'을 쓰지 마십시오. 결과적으로 "힙에서 일부 메모리를 할당 한 다음 힙에서 메모리가 유실되었음을 잊어 버리십시오"라고 말하고있는 것입니다. 그런 다음 참조가 아닌 값에 할당하면 복구 할 수없는 메모리 누출이 발생합니다. 참조로 지정해도 정리에는'delete & r'이 필요합니다. 이것은 끔찍한 비 관례입니다. –

답변

12

r = *sp;은 생각하는대로하지 않습니다. 즉, 줄 1의 힙에 만든 익명 int 개체에 할당합니다. C++에서 참조를 다시 연결할 수 없습니다. 여기

표준이 참조 표현식을 평가에 대한 말씀입니다 : 표현식이 처음 유형 "T 참조"가

경우, 유형 전에 더 분석 T으로 조정된다. 표현식은, 으로 표시된 객체 또는 함수를 지정하며 표현식은 표현식에 따라 lvalue 또는 xvalue입니다.

"참조 자체"로 이동하는 방법은 없습니다. C++에는 존재하지 않습니다.

어쩌면이 코드가 명확하게됩니다 r = b 정말 a = b을 의미하기 때문에

int a = 42; 
int b = 97; 

int&r = a; // r is just an alias (another name) for a 
    r = b; // assigns b to a (does NOT bind r to b, that's impossible in C++!) 

을 마지막 줄을 실행 한 후, 모두 ab는 97이 포함되어 있습니다.

+0

그래서 마치 이런 식으로 코딩하고있는 것처럼 보입니까? : ((& r) =() – JnBrymn

+1

아니요, 마치 코딩하는 것처럼 ... 숨을 참 으세요. 'r = * sp'.'r '는 이미 존재하는 값에 대해 새로 할당 된 이름으로 가장 잘 생각됩니다. 공유 포인터가 가리키는 값을 읽고'r '이 참조하는 메모리 덩어리에 할당합니다. 'r'은 다른 메모리 덩어리를 가리키는 것이 불가능하며, 불가능합니다 .'r'은 ** value **의 새로운 이름입니다. 값은 움직이지 않습니다 (적어도 0x 이전이 아님). –

+0

@FredOverflow So 내 예제에서는 해당 shared_ptr 삭제 된 후 참조를 사용하여 확인을 나타냅니다. 삭제 된 값을 참조하는 참조를 어떻게 동작을 정의 할 수 있습니다 ... 내 현재 경우에 그것은 될 것이라고 이해하지 못합니다. – JnBrymn

2

p가 정의되어, R은 두 번째 경우 사본

int& r = *(new int(0)); 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    r = *sp; // copy 
    cout << "r=" << r << endl; 
} 
cout << "r=" << r << endl << endl; 

int* p; 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    p = &*sp; 
    cout << "*p=" << *p << endl; 
} 
cout << "*p=" << *p << endl; // Undefined, pointer points to deleted int 
+0

* (new int (0))을 계속 가리키면 어떻게 100을 인쇄 할 수 있습니까? – ronag

+0

@ronag : 포인터가 가리키는 값을 참조 점이 복사 된 값으로 복사합니다. –

+0

문제를 시정 해 주셔서 감사합니다. – ronag

0

이다하여 int -object는 소멸된다. 첫 번째 경우에는 그렇지 않습니다.

첫 번째 경우에는 외부 범위에 new 인 새 int 개체를 만듭니다. 내부 범위에서 두 번째 int -object를 만들면 shared_ptr도 생성되고 그 다음 int -object를 소유하게됩니다. 이 shared_ptr은 내부 범위를 닫을 때 범위를 벗어나면 소멸됩니다.shared_ptr 소멸자는 참조하는 객체도 파괴합니다. shared_ptr (원래 객체에서 생성 된 것)이 더 이상 int 객체를 참조하지 않기 때문입니다. 그게 다 괜찮아. 그러나 해당 범위의 중간에 r의 값을 *sp (100)의 값으로 다시 지정합니다. 따라서 이 소멸되기 전에 *sp의 값을 r으로 저장합니다.

참고 : 첫 번째 코드 줄에서 수행하는 방식과 마찬가지로 int 개체를 만드는 것이 확실한 스타일입니다. 해당 int 개체를 명시 적으로 삭제하지 않으면 이는 메모리 리크입니다. 그것을 파괴하는 방법은 r 기호가 나중에 지금도 삭제 된 int 객체를 참조하기 때문에 실제로보기 흉한 delete &r이 될 것입니다. 이 작업을하지 마십시오!

두 번째 경우에는 처음에 int 포인터를 만들지 만 int 개체는 만들지 않습니다. 내부 범위는 이전과 거의 동일하지만 이번에는 새 int 개체의 값을 외부 범위 변수 (p)에 저장하지 않고 int 개체의 주소를 저장합니다. int 개체가 내부 범위의 끝에서 (이전과 같은 이유로) 파괴되면서 p은 더 이상 기존의 int 개체를 가리 키지 않지만 이전에 한 번만 int 개체를 보유한 메모리 장소를 가리 킵니다. *p에서 얻은 값은 정의되지 않았습니다. 더 이상 보유하지 않는 메모리 위치를 역 참조 할 때 여전히 100을 얻고 다른 값을 얻을 수 있으며 여기서 프로그램을 크래시 할 수도 있습니다 (분할 오류). 여전히 기존의 객체를 참조하기 때문에,

참조가 남아 :

그래서 요약 및 최종 질문에 대답합니다. 포인터는 더 이상 존재하지 않는 객체를 가리 키기 때문에 그렇지 않습니다.

관련 문제