2013-02-19 2 views
0

수업이 있습니다. 이 클래스가 인스턴스화 될 때 인스턴스를 목록에 추가하려고합니다. 개체가 삭제되면 목록에서 삭제됩니다.목록에서 개체를 자동으로 추가 및 제거

그래서 객체에 공유 포인터를 제공합니다. 그런 다음 공유 포인터에 약한 포인터 목록이 있습니다. 객체가 생성되면, 자신에 대한 공유 포인터를 생성하고, 그것에 약한 포인터를 만들고, 약한 포인터를리스트에 넣습니다.

개체가 파괴되면 공유 포인터도됩니다. 목록에있는 멤버에 액세스하려고 시도 할 때마다 만료되지 않았으며 사용 횟수가 0이 아닌지 확인합니다.이 작업에도 불구하고 목록 멤버가 삭제되면 여전히 충돌이 발생합니다. 왜? 나는 주변을 얻을 수 있습니까?

#include <iostream> 
#include <memory> 
#include <vector> 

class test 
{ 
    private: 
     std::shared_ptr<test> self; 

    public: 
     int val; 
     test(int set); 

     test(test &copy) = delete; // making sure there weren't issues 
            // with a wrong instance being deleted 
}; 

std::vector<std::weak_ptr<test>> tests; 

test::test(int set): 
    val(set) 
{ 
    this->self = std::shared_ptr<test>(this); 

    tests.push_back(std::weak_ptr<test>(this->self)); 
} 

void printTests() 
{ 
    for (auto i = tests.begin(); i != tests.end(); i++) 
    { 
     if (i->use_count() == 0 || i->expired()) 
     { 
      tests.erase(i); 
      continue; 
     } 

     std::cout << i->lock()->val << std::endl; 
    } 

    std::cout << std::endl; 
} 

int main(int argc, char **argv) 
{ 
    { 
     test t(3); 

     std::cout << "First tests printing: " << std::endl; 

     printTests(); 
    } // SEGFAULTS HERE 

    std::cout << "Second tests printing: " << std::endl; 
    printTests(); 

    return 0; 
} 

은 다음이 프로그램의 출력이 될 때 :

First tests printing: 
3 

Segmentation fault (core dumped) 
+2

나는 것입니다 거의 * 보장 * 당신'그 this-> 자기 = 표준 : : shared_ptr의 (이)'특히 실물,'테스트 t 있기 때문에, 당신이 생각하는 일을하지 않습니다 (3)', * stack *에있다. – WhozCraig

+0

스택에 있다는 것은 테스트가 범위 끝에서 파괴된다는 것을 의미합니다. 이는 내가 원하는 것입니다.내가하고 싶은 일을 내가 어떻게 또 할 것인가? – Avi

+1

''std :: shared_ptr <>'는 공유 된 ptr obj가 파괴 될 때 포함 된 객체 포인터로 무엇을한다고 생각합니까? – WhozCraig

답변

3

문제가 어떻게 자기 포인터를 만들 함께 ,

T가 배열 유형이 아닌 경우 포인터 p를 소유하는 shared_ptr을 생성합니다. 은 ... P는는 C를 통해 할당 된 객체 ++ 새로운 표현에 대한 포인터이거나 따라서 문제는 shared_ptr 개체가 도착 그렇게되면 스택 개체의 소유권을하고 있음을 0

해야합니다 destructed (그리고 함께 shared_ptr), shared_ptr은 스택에있는 delete 개체를 찾으려고합니다. 이것은 유효하지 않습니다.

사용 사례에 따라 testvector보다 오래 걸릴 것으로 예상되는 경우 this을 저장할 수 있습니다.

+0

우수. 그렇다면 어떻게해야합니까? 나는이 객체를 파생해야하기 때문에 소멸자에서 자기가 가리키는 것을 대체 할 수 없다. – Avi

+1

@Avi : 소멸자가 목록 항목을 제거하지 않는 이유는 무엇입니까? –

+0

필자가 두 번 말한 이유는 다음과 같습니다. 테스트를 유도 할 수 있어야하며 각 파생 된 객체의 소멸자에 대해 해당 코드를 다시 작성하지 않아도됩니다. 이것은 파생 된 객체의 코더에서 목록을 숨기는 것으로 여기에서하려고하는 목적을 무효화합니다. – Avi

1

이 줄 문제입니다 : 여기 내 SSCCE의

tests.erase(i); 

삭제 된 가리키는 반복자 요소가 유효하지 않으므로 더 이상 증가시킬 수 없습니다. 다행히, erase 새로운 반복자를 반환 당신이 사용할 수있는 다음 documentation에 따르면, shared_ptr이 생성자를 생성

this->self = std::shared_ptr<test>(this); 

:

auto i = tests.begin(); 
while (i != tests.end()) 
{ 
    if (i->use_count() == 0 || i->expired()) 
    { 
     i = tests.erase(i); 
    } 
    else { 
     std::cout << i->lock()->val << std::endl; 
     ++i; 
    } 
} 
+0

그런 경우 문제가 발생한 반복기에 액세스 할 수 있습니다. 맞습니까? – Avi

+0

downvote 이유는 무엇입니까? 이 문제가 유일한 문제가 아니더라도이 대답은 정확합니다. –

2

나는 그가 시도한 방법과 다른 방법을 사용하더라도 그의 원래 문제에 대한 해결책에 관심이 있다고 생각합니다. 다음은 생성 될 때 전역 목록에 개체를 추가하고 개체를 삭제할 때 전역 목록을 제거하는 방법에 대한 간단한 예제입니다. 한가지 기억해야 할 것은 기본 클래스에 추가하는 모든 생성자에서 AddList를 호출해야한다는 것입니다. 클래스 외부에서 목록에 액세스 할 수 있는지 여부를 알지 못 했으므로 getter 함수를 추가하여 비 const 반복기를 목록에 반환했습니다.

class MyClass 
{ 
private: 
    static std::list<MyClass*> mylist; 
    std::list<MyClass*>::iterator mylink; 

    // disable copy constructor and assignment operator 
    MyClass(const MyClass& other); 
    MyClass& operator = (const MyClass& other); 

    void AddList() 
    { 
     mylink = mylist.insert(mylist.end(), this); 
    } 

    void RemoveList() 
    { 
     mylist.erase(mylink); 
    } 

public: 
    MyClass() 
    { 
     AddList(); 
    } 

    virtual ~MyClass() 
    { 
     RemoveList(); 
    } 

    static std::list<MyClass*>::iterator GetAllObjects_Begin() 
    { 
     return mylist.begin(); 
    } 

    static std::list<MyClass*>::iterator GetAllObjects_End() 
    { 
     return mylist.end(); 
    } 

    virtual std::string ToString() const 
    { 
     return "MyClass"; 
    } 
}; 

class Derived : public MyClass 
{ 
    virtual std::string ToString() const 
    { 
     return "Derived"; 
    } 
}; 

std::list<MyClass*> MyClass::mylist; 


int main() 
{ 
    std::vector<MyClass*> objects; 
    objects.push_back(new MyClass); 
    objects.push_back(new MyClass); 
    objects.push_back(new Derived); 
    objects.push_back(new MyClass); 

    for (std::list<MyClass*>::const_iterator it = MyClass::GetAllObjects_Begin(), end_it = MyClass::GetAllObjects_End(); it != end_it; ++it) 
    { 
     const MyClass& obj = **it; 
     std::cout << obj.ToString() << "\n"; 
    } 

    while (! objects.empty()) 
    { 
     delete objects.back(); 
     objects.pop_back(); 
    } 
} 
+0

예, 대체 솔루션이 좋았지 만 운 좋게도 제가 구현할 수있었습니다. 응답 해 주셔서 감사합니다. – Avi