2012-07-03 4 views
2

나는 이것을 이해할 수 없다. 내가 간단한 것을 놓치고있는 것처럼 보인다고? 나는이 시점에서 그렇게 MakePointToSameValue 그에 넣어 무엇을 (1)shared_ptr의 복사본을 다른 shared_ptr과 동일하게 만드는 방법은 무엇입니까?

  • 즉 a.ptr
  • 과 동일한에게 모두 b.ptr 및 c.ptr 점은 a.ptr.get() == b.ptr.get() == c.ptr.get()
  • 값은 원래 지적 b.ptr에 의해 c.ptr이 삭제됨

? 그것은 C를 변경하지 않기 때문에, 작동하지 않습니다 PTR 복사

struct Test 
{ 
public: 
    Test(int val) : 
    ptr(std::make_shared<int>(val)) 
    { 
    } 

    void MakePointToSameValue(Test& other) 
    { 
    //what do I put here? 
    //other.ptr = this->ptr; //doesn't do it 
    } 

private: 
    std::shared_ptr<int> ptr; 
}; 

Test a(0); 
Test b(5); 
Test c(b); 

b.MakePointToSameValue(a); 

//(1) 

은 (물론, c.ptr는이 refcount는 하나 감소 것있다). 단순함을 위해서 int을 사용하고 있지만 복사 불가능한 유형에서는 작동해야합니다.

왜? 필자는 일종의 컴파일러에서 사용할 값, 모든 유형의 값을 나타내는 클래스를 보유하고 있습니다. 실제 값이나 저장 방법은 인스턴스화 될 때 알려집니다. 알려진 유일한 유형입니다. 따라서 클래스는 나중에 결정되는 값에 대한 자리 표시자를 포함하는 shared_ptr을 저장합니다 (포인터 또는 참조로 전달 될 때 함수 정의의 인수를 컴파일하는 것에 해당 : 컴파일러는 형식 만 알고, 그 이상은 없습니다). 런타임에는 자리 표시자를 실제 값으로 대체해야합니다.

편집 오늘의 새로운 시작을 내놓으시기 바랍니다. 나는 그것이 단순하다는 것을 알았다.

void MakePointToSameValue(Test& other) 
{ 
    other.ptr.swap(ptr); 
    ptr.reset(); 
    ptr = other.ptr; 
} 

추가 질문은 다음과 같습니다. 표준 준수 포인터에 대해 예상대로 작동합니까?

+0

정확히 무엇입니까? –

+4

두 단계의 간접 참조가 필요합니다. –

+0

@CatPlusPlus 마지막 단락을 참조하십시오. – stijn

답변

3

여기에는 두 가지 수준의 간접 참조가 필요합니다. 모든 shared_ptr 개체가 카운트와 실제 값에 대한 포인터를 포함하는 일반적인 메타 데이터 블록을 가리키는 것이 맞지만, 해당 블록을 다른 개체를 가리 키도록 업데이트하려고하면 이제 두 개의 메타 데이터 블록을 가리키게됩니다. 동일한 가치로, 각각은 참조 횟수가 무엇인지에 대한 각각의 다른 생각을 가지고 있습니다.각 메타 데이터 블록을 사용하는 shared_ptr 개체의 참조 번호와 일치한다는 의미에서 올바른 숫자가 있으므로 각 블록의 수가 0에 도달하지만 마지막 블록에 도달하는 블록을 알 수있는 방법이 없습니다. 0 인 경우 (따라서 값을 삭제해야 함). 그래서 shared_ptr 현명하게 메타 데이터 내에서 객체 포인터를 변경할 수 없습니다. shared_ptr 만 새 메타 데이터 블록, 새 수, 새 개체와 연결할 수 있습니다. 그리고 같은 객체에 대한 다른 포인터는 영향을받지 않습니다.

올바른 방법은 간접 참조의 두 번째 계층 (shared_ptr<shared_ptr<int> >)을 사용하는 것입니다. 그렇게하면 정확히 하나의 메타 데이터 블록이 있고 각 객체에 정확히 하나의 개수가 있습니다. 업데이트는 중간 shared_ptr에서 수행됩니다.

1

음, 귀하의 요구 사항을 이해하는 한, shared_ptr에는 이러한 메커니즘이 포함되어 있지 않습니다. 정규 유형도 마찬가지입니다. 이 동작을 원한다면 직접 코딩해야합니다. 내 제안 : 개인 정적 추가 std::list<std::weak_ptr<Test>> registry; 생성자의 registry 목록에 각 인스턴스를 추가하여 Test 인스턴스를 등록하고 소멸자에서 해당 인스턴스를 제거하십시오.

그런 다음 MakePointToSameValue에서 해당 레지스트리를 사용하여 모든 인스턴스를 반복하고 ptr 값을 다시 설정하십시오.

효율성에 관심이 있고 3보다 많은 인스턴스가있는 경우 listunordered_set으로 바꿔야합니다. Test 클래스에 shared_ptr 대신 unique_ptr을 사용하십시오.

추가 질문에 대한 답변 : 아니오, 작동하지 않습니다. reset()의 설명서를 살펴보면 특정 인스턴스 shared_ptr을 다시 설정합니다. 다른 인스턴스와 아무런 관련이 없으며 아무 것도 알지 못합니다. 제어 블록의 참조 카운트가 0에 도달하면 pointee를 추가로 파괴하지만 그게 전부입니다.

+0

y u'std :: list'? 그건 바보 야. 예를 들어'unordered_set'를 사용하여 O (1) 제거 및 추가를 얻을 수 있습니다. – Puppy

+0

예. 그게 더 효율적인지 여부는 인스턴스의 수에 달려 있습니다. stijn은 우리에게 아무런 리드도주지 않았습니다 : 단지 3 개라면 내 베팅은 여전히 ​​목록에 있습니다. 그렇지 않으면, 확실합니다. –

+0

흠, shared_ptr에서 이것이 가능해야한다고 생각 했나요? 내 말은, 필요한 모든 것을 담고있다. (모든 복사본은 같은 포인터/내부적으로 refcount 객체를 가진다.) 나는 atm을 사용하는 방법을 알아낼 수 없다. – stijn

관련 문제