2010-03-06 3 views
7

모든 메모리 누수를 막으려 고합니다 (방대한). 나는 STL을 처음 사용한다. 3 세트가있는 클래스 라이브러리가 있습니다. 또한 세트에 정보를 추가하기 위해 라이브러리 클래스에 새로운 메모리를 많이 생성하고 있습니다. ...메모리 누수 - STL 세트

세트를 할당 해제해야합니까? 그렇다면 어떻게? 여기

내가 소멸자를 위해 무엇을해야하는지 확실하지 오전 library.h

#pragma once 

#include <ostream> 
#include <map> 
#include <set> 
#include <string> 
#include "Item.h" 

using namespace std; 

typedef set<Item*>    ItemSet; 
typedef map<string,Item*>  ItemMap; 
typedef map<string,ItemSet*> ItemSetMap; 

class Library 
{ 

public: 
    // general functions 

    void addKeywordForItem(const Item* const item, const string& keyword); 
    const ItemSet* itemsForKeyword(const string& keyword) const; 
    void printItem(ostream& out, const Item* const item) const; 

    // book-related functions 

    const Item* addBook(const string& title, const string& author, int const nPages); 
    const ItemSet* booksByAuthor(const string& author) const; 
    const ItemSet* books() const; 

    // music-related functions 

    const Item* addMusicCD(const string& title, const string& band, const int nSongs); 
    void addBandMember(const Item* const musicCD, const string& member); 
    const ItemSet* musicByBand(const string& band) const; 
    const ItemSet* musicByMusician(const string& musician) const; 
    const ItemSet* musicCDs() const; 

    // movie-related functions 

    const Item* addMovieDVD(const string& title, const string& director, const int nScenes); 
    void addCastMember(const Item* const movie, const string& member); 
    const ItemSet* moviesByDirector(const string& director) const; 
    const ItemSet* moviesByActor(const string& actor) const; 
    const ItemSet* movies() const; 
    ~Library(); 
}; 

입니까?

Library::~Library() 
{ 


} 

또한 문자열 세트를 올바르게 할당합니까?

#ifndef CD_H 
#define CD_H 
#pragma once 
#include "item.h" 
#include <set> 


typedef set<string> StringSet; 


class CD : public Item 
{ 
public: 

    CD(const string& theTitle, const string& theBand, const int snumber); 
    void addBandMember(const string& member); 
    const int getNumber() const; 
    const StringSet* getMusician() const; 
    const string getBand() const; 
    virtual void print(ostream& out) const; 
    string printmusicians(const StringSet* musicians) const; 

    ~CD(); 


private: 

    string band; 
    StringSet* music; 

    string title; 
    int number; 

}; 

ostream& operator<<(ostream& out, const CD* cd); 

#endif 

나는 많은 메모리를 만드는 오전 라이브러리 클래스의

#include "CD.h" 

using namespace std; 

CD::CD(const string& theTitle, const string& theBand, const int snumber) 
: Item(theTitle), band(theBand),number(snumber), music(new StringSet) 
{ 



} 

CD::~CD() 
{ 

    delete []music; 

} 

cd.cpp하지만 소멸자가 정리 해달라고? 예 :

const Item* Library::addBook(const string& title, const string& author, const int nPages) 
{ 

    ItemSet* obj = new ItemSet(); 
    Book* item = new Book(title,author,nPages); 
    allBooks.insert(item); // add to set of all books 
    obj->insert(item); 

참고 : 나는 복사 생성자가 없습니다. 나는 심지어 하나가 필요한지 또는 어떻게 최상을 추가하는지 잘 모르겠습니다. 내 소멸자 중 하나라고 불리는 것 같아 ..

+0

짧은 대답 : 코드에서'*'문자의 모든 인스턴스를 검색하고 삭제하십시오. C++에서 포인터를 사용할 필요가 거의 없습니다. 당신이 할 때마다, 당신은 기억 누출을 요구하고 있습니다. – jalf

+4

표준 형식을 사용하는 경우에도 C++에서 포인터를 사용해야하는 경우가 많이 있습니다. – Xorlev

+0

이 경우'Item'은 저장된 객체의 기본 클래스이므로'ItemSet'과'ItemMap'에 포인터를 저장해야합니다. 스마트 포인터를 저장하면 이러한 누수가 수정됩니다. 'ItemSetMap'은 단지 set 객체를 포함해야합니다. –

답변

3

세트의 각 요소에 대해 메모리를 확보해야합니다. 컨테이너는 당신을 위해 그렇게하지 않을 것이고, 데이터가 소유하고 있는지 아닌지를 알 수 없으므로 안됩니다. 다른 것으로 소유 된 객체에 대한 포인터를 보유하고있을 수도 있습니다.

이것은 모든 STL 컨테이너를 할당 해제하는 일반적인 무료 함수입니다.

template <typename T> 
void deallocate_container(T& c) 
{ 
    for (typename T::iterator i = c.begin(); i != c.end(); ++i) 
    delete *i; 
} 

// Usage 
set<SomeType*> my_set; 
deallocate_container(my_set); 
my_set.clear(); 
+0

하지만 RTTI가 필요합니다. – pajton

+0

왜 이렇게 RTTI가 필요한가요? –

+0

아마도 가상 소멸자를 가지는 클래스가 필요할 것입니다. 어쨌든 대부분의 클래스에는 가상 소멸자가 필요합니다. 문제는이 deallocate_container 함수, IOW가 아니라 클래스의 속성입니다. 하나의 문제 -하지만 각 항목에 대한 키와 데이터를 가지고있는 std :: map에서 작동할까요? 잠재적으로 포인터일까요? – Steve314

1

당신의 모든 코드를 통과하지 못했지만 처음 몇 라인에서 포인터 세트를 유지하고있는 것처럼 보입니다. 포인터를 보유하고있는 STL 컨테이너가 있고 포인터에 물건을 넣기 위해 new을 사용할 때마다 delete를 사용하여 이러한 포인터를 할당 해제해야합니다. STL은 그렇게하지 않습니다. 실제로 STL은 포인터라는 사실조차 모릅니다.

또 다른 옵션은 포인터를 전혀 사용하지 않고 단지 개체 집합을 사용하고이를 만들 때 new을 사용하지 않는 것입니다. 그냥 스택에 생성하고 세트로 복사하십시오.

0

소멸자에서 포인터가 포함 된 stl 컬렉션을 반복하고 삭제해야합니다. 이와 같이 :

1

음,이 바보 같은 코멘트 수 있지만 당신이 정말로 모든 물건 힙 할당이 필요 할 수도 있습니다 (일명. 사용하여 포인터와 새를?)

당신은 그냥 일반 인스턴스를 사용할 수 없습니다 ? RAII는 더 쉬운 코드와 메모리 누출을 허용합니다. 예를 들어

은이 :이 방법

using namespace std; 

typedef set<Item>    ItemSet; 
typedef map<string,Item>  ItemMap; 
typedef map<string,ItemSet> ItemSetMap; 

class Library 
{ 

public: 
    // general functions 

    void addKeywordForItem(const Item & item, const string& keyword); 
    ItemSet itemsForKeyword(const string& keyword) const; 
    void printItem(ostream& out, const Item & item) const; 

    // book-related functions 

    Item addBook(const string& title, const string& author, int nPages); 
    ItemSet booksByAuthor(const string& author) const; 
    ItemSet books() const; 

    // music-related functions 

    Item addMusicCD(const string& title, const string& band, int nSongs); 
    void addBandMember(const Item & musicCD, const string& member); 
    ItemSet musicByBand(const string& band) const; 
    ItemSet musicByMusician(const string& musician) const; 
    ItemSet musicCDs() const; 

    // movie-related functions 

    Item addMovieDVD(const string& title, const string& director, int nScenes); 
    void addCastMember(const Item & movie, const string& member); 
    ItemSet moviesByDirector(const string& director) const; 
    ItemSet moviesByActor(const string& actor) const; 
    ItemSet movies() const; 
    ~Library(); 
}; 

는 소멸자는 엄격하게 아무것도없고 메모리 누수를하지 않는다한다. 포인터를 사용하는 대부분의 경우 쉽게 피할 수 있으며, 분명히해야합니다!

0

다른 사람들도 언급했듯이 포인터를 할당 해제해야합니다. set 소멸자는 일반적으로이 작업을 수행하지 않습니다. 그렇지 않으면이 작업을 수행하려면 boost::scoped_ptr 또는 std::tr1::shared_ptr을 사용하십시오. 여기서 사용자 지정 삭제자를 지정하여이 작업을 수행 할 수 있습니다.

4

STL 컨테이너는 포인터를 보유하도록 설계되지 않았습니다.

부스트 포인터 컨테이너를보십시오. 이 A 테이너는 포인터를 보유하도록 설계되었습니다.

#include <boost/ptr_container/ptr_set.hpp> 
#include <boost/ptr_container/ptr_map.hpp> 

http://www.boost.org/doc/libs/1_42_0/libs/ptr_container/doc/ptr_set.html

컨테이너가 보유하고 컨테이너가 범위를 벗어나 때 삭제됩니다 있도록 포인터를 소유하고 있습니다. 그러나 컨테이너에 대한 아름다운 점은 참조를 통해 객체에 액세스하므로 모든 표준 알고리즘이 특별한 어댑터없이 작동한다는 것입니다.

typedef boost::ptr_set<Item>    ItemSet; 
typedef boost::ptr_map<string,Item>  ItemMap; 
typedef boost::ptr_map<string,ItemSet> ItemSetMap; 

추신. 정확하게 말하기는 힘들지만 너무 많은 인터페이스가 포인터를 반환하는 것처럼 보입니다. C++에서는 실제로 포인터를 반환하거나 포인터를 전달하는 것이 거의 없습니다. 인터페이스는 일반적으로 객체/참조 또는 스마트 포인터를 가져야합니다 (일반적으로 순서는 다르지만 상황에 따라 다릅니다).

개체 소유자의 명확한 표시가 없으므로 정리가 문제가되므로 포인터를 사용하는 것이 최후의 수단이어야합니다 (따라서 막대한 메모리 누수가 발생합니다).

+0

특히 마지막 수단 인 포인터에 대한 +1 –

1

다른 질문 (예 : https://stackoverflow.com/questions/2376099/c-add-to-stl-set)에 게시 한 코드 중 일부를 보면 항목이 여러 개의 글로벌 ItemSet 개체에 저장되어 있습니다. 이것은 좋은 디자인이 아닙니다. 실제로는 Library 객체의 일부 여야합니다. 논리적으로는 객체에 속하기 때문입니다.

메모리 누수를 해결하는 가장 좋은 방법은 원시 포인터를 처리하는 것이 아니라 스마트 포인터를 세트에 저장하거나 Martin York이 제안한대로 Boost 포인터 컨테이너를 사용하는 것입니다. 또한 ItemSetMap 개체에는 포인터가 아닌 Set 개의 개체가 있어야합니다. 포인터를 저장할 이유가 전혀 없습니다. 당신이 정말로 포인터를 저장해야하는 경우

, 다음 소멸자 내용을 삭제하기 위해 각각의 세트를 통해 걸어해야합니다

void Purge(ItemSet &set) 
{ 
    for (ItemSet::iterator it = set.begin(); it != set.end(); ++it) 
     delete *it; 
    set.clear(); // since we won't actually be destroying the container 
} 

void Purge(ItemSetMap &map) 
{ 
    for (ItemSetMap::iterator it = map.begin(); it != map.end(); ++it) 
     delete it->second; 
    map.clear(); 
} 

Library::~Library() 
{ 
    Purge(allBooks); 
    Purge(allCDs); 
    // and so on and so forth 
} 

을하지만 정말 그냥 모든 사람들이 응답에 대한로, 그 일을 할 방법 아니다 당신의 질문이 지적되었습니다. StringSet에 관해서는

, 당신은 일반 new하지 new[]로 만든, 그래서 당신은 일반 delete하지 delete[]으로 삭제해야합니다. 또는, 더 나은 여전히 ​​ music 포인터 대신 StringSet 개체를 만들 수 있습니다, 그럼 당신은 전혀 소멸자가 필요하지 않습니다. 다시 한번, 원시 포인터를 통한 메모리 관리와 delete의 수동 사용은 오류가 발생하기 쉽기 때문에 가능하면 피해야합니다.

+0

아직 메모리 누수가 많이 있습니다. –

+0

또한 typedef를 설정했습니다 \t StringSet; StringSet * Moviecast; 나는 그것에 삭제 MoviCast를 사용할 수 있습니까? 또는 iterate해야합니까? –

+0

아니요,'set '을 반복 할 필요가 없습니다. 객체가 포함되어 있고 그 자체를 할당 해제 할 것이기 때문입니다. 'new'를 사용하여 할당 한 객체 만 삭제하면되므로 필요할 때마다 그렇게하지 않아야합니다. –