实现迭代映射的类迭代器

时间:2015-12-24 12:46:53

标签: c++ dictionary memory-leaks iterator

如何创建一个迭代通用映射节点而不会导致内存泄漏的类迭代器? 我的地图上有一个名为" pair"这是通用的,有价值和关键。 也是一个被称为节点的类,它包含一对和指向下一个节点和前一个节点的指针。 地图本身包含头节点。和地图大小.. 这段代码工作,我的问题是它有内存泄漏。 因为迭代器是一个类(我们被要求实现为一个类,而不仅仅是一个节点),它包含一个指向具有一对的Node的指针。每当我们想要使用迭代器析构函数时,我们就不能通过删除节点来删除该对,因为它会完全删除该对和导致元素在地图中丢失的节点。 你能给出一些如何在没有内存泄漏的情况下正确实现的建议吗? 并且非常重要:map函数end()应该返回一个不是map元素之一的随机值(这就是为什么我将它设置为NULL)

template <class KeyType, class ValueType, class CompareFunction = std::less<KeyType> >
class MtmMap {
public:

    class Pair {
    public:
        Pair(const KeyType& key, const ValueType& value)
            : first(key), second(value) {}
        Pair()
            : first(NULL), second(NULL) {}
        ~Pair(){}
        const KeyType first;
        ValueType second;
        bool operator==(const Pair& pair)const{
            if(pair.first==this->first&&pair.second==this->second){
                return true;
            }
            return false;
        }
        bool operator!=(const Pair& pair)const{
            if(this==pair){
                return false;
            }
            return true;
        }
        Pair& operator=(const Pair& pair){
            if(this==&pair){
                return *this;
            }
            this->first=pair.first;
            this->second=pair.second;
            return *this;
        }
        Pair& operator=(ValueType val){
            this->second=val;
            return *this;
        }
        const KeyType& getFirst(){
            KeyType* keyPointer=&first;
            return (first);
        }
        ValueType getSecond(){
            ValueType* valPoiner= &second;
            return (valPoiner);
        }
    };

    class Node {
        public:
            Pair* element;
            //int plc;
            Node* next;
            Node* before;
            Node() :element(), next(NULL),before(NULL){}

            Node(const Node& copyNode) :
                    element(new Pair(*(copyNode.element))), next(
                            copyNode.next) ,before(copyNode.before){
            }
            Node& operator++(){
                if(this->next){
                return(this->next);
                }
                Node* node=new Node;
                node->next=NULL;
                node->element=NULL;
                //node->first=NULL;
                return(node);
            }
            Node operator++(int n){
                Node result=*this;
                ++this;
                return result;
            }
            Node& operator--(){
                return(this->before);
            }
            bool operator==(const Node& node)const{
                if(node.before==this->before&&node.element==this->element&&node.next==this->next){
                    return true;
                }
                return false;
            }
            bool operator!=(const Node& node)const{
            if(this==node){
                return false;
            }
            return true;
            }
            Node& operator=(const Node& node){
                if(this==&node){
                    return *this;
                }
                this->before=node.before;
                this->element=node.element;
                this->next=node.next;
                return *this;
            }

            }

        };

    class iterator{
    public:
        Node* p;
        iterator():p(){}
        iterator(const iterator& it):p(it.p){}
        ~iterator(){
        }
        iterator& operator++(){
        this->p=this->p->next;
        if(this->p){
            return *this;
        }
        this->p=NULL;
        return *this;
        }
        iterator operator++(int n){
            iterator result=*this;
            ++*this;
            return result;
        }
        iterator& operator=(const iterator& it){
            if(this==&it){
                return *this;
            }
            this->p=it.p;
            return *this;
        }

        bool operator==(const iterator& iterator)const{
            if(this->p==iterator.p){
                return true;
            }
            return false;
        }
        bool operator!=(const iterator& iterator)const{
            if(this->p!=iterator.p){
                return true;
            }
            return false;
        }
        const Pair& operator*(){
            if(*this==end()){
                throw MapElementNotFoundException();
            }
            return *p->element;
        }
        iterator& begin(){
            while(p->before!=NULL){
                p--;
            }
            return *this;
        }
        iterator& end(){
            iterator* it=new iterator();
            it->p=NULL;
            return *it;

        }



    };

    int mapSize;
    Node* head;
    iterator iter;
    ValueType initializer;
    CompareFunction compareFunc;

    MtmMap(ValueType val):mapSize(0),head(),iter(),initializer(val){}

2 个答案:

答案 0 :(得分:0)

您需要使用准确反映目录结构的相对路径。例如:

include my_set/Makefile
include tests/Makefile

# ...

TEST_OBJS1 = tests/cache_test.o cache.o 
TEST_OBJS2 = tests/memcache_test.o memcache.o cache.o user.o
TEST_OBJS3 = my_set/my_set_test.o my_set/my_set.o

# ...

基本上,您要创建一个&#34; Makefile&#34;在每个子目录中,您包括&#34;并定义了构建这些子目录中每个目标的规则(以及使用相对于规则中根Makefile目录的路径),在顶级Makefile中,您将类似地通过其路径引用这些文件/目标相对于顶级Makefile目录(而不是文件名)。

答案 1 :(得分:0)

给出目录布局:

main/
    cache.c
    cache.h
    memcache.c
    memcache.h
    user.c
    user.h
    my_set/
        my_set.c
        my_set.h
        my_set_test.c
    tests/
        memcache_test.c
        cache_test.c

定义宏时,如果只评估一次,请使用:=而不是=

在为外部可执行文件提供宏名称时,始终提供完整路径

注意:答案在make rule命令的开头包含空格 必须用tab替换才能实现makefile语法

问题无法指定某些头文件的位置,并且无法指示某些.c文件使用哪些头文件。

假设所有未明确位于目录布局中的头文件实际上位于'main /'目录中。

这些显式编译规则是未知的头文件依赖关系具有此文本??? which header files ???

建议的makefile内容如下:

#CC=gcc
CC := /usr/bin/gcc
RM := /usr/bin/rm

# you stated the executables were to be in the main directory
#EXEC1 = /tests/cache_test
#EXEC2 = /tests/memcache_test
#EXEC3 = /my_set/my_set_test
EXEC1 := cache_test
EXEC2 := memcache_test
EXEC3 := my_set_test

# when object in sub directory, include the directory path
TEST_OBJS1 := tests/cache_test.o cache.o
TEST_OBJS2 := tests/memcache_test.o memcache.o cache.o user.o
TEST_OBJS3 := my_set/my_set_test.o my_set/my_set.o

LIBS         := -L. -lmtm
DNDEBUG_FLAG := -DNDEBUG

CFLAGS := -Wall -Werror -pedantic-errors -std=c99 -g

# need to tell ''make'' that certain targets do not produce a output file
.PHONY : all clean

# first/default target in makefile
# it has dependencies on each of the 3 executables
#   so, by default, the three executables will be generated
all: $(EXEC1) $(EXEC2) $(EXEC3)
        @echo "all done"

# link rules needs any 'special' library path and library name parameters
$(EXEC2): $(TEST_OBJS2)
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) $(TEST_OBJS2) -o  $@  $(LIBS)

$(EXEC1): $(TEST_OBJS1)
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) $(TEST_OBJS1) -o  $@  $(LIBS)

$(EXEC3): $(TEST_OBJS3)
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) $(TEST_OBJS3) -o  $@  $(LIBS)


# compile rules have no use for library path and library name parameters
#     they do have use for where to find the user supplied header files
#     especially if those header files are not in the current directory

# only compile one file in each explicit compile rule

# always place the source file name as the first dependency parameter
#      so '$<' can be used to reference it

cache.o: cache.c cache.h list.h set.h
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I.

user.o: user.c user.h set.h list.h
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I.

memcache.o: memcache.c cache.h list.h set.h user.h memcache.h map.h
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I.

my_set/my_set.o: my_set/my_set.c my_set/my_set.h list.h
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I. -Imy_set/.

tests/cache_test.o : tests/cache_test.c ??? which header files ???
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I. -Itests/.

tests/memcache_test.o : tests/memcache_test.c ??? which header files ???
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I. -Itests/.

my_set/my_set_test.o : my_set/my_set_test.c ??? which header files ???
        $(CC) $(CFLAGS) $(DNDEBUG_FLAG) -c $< -o $@  -I. -Imy_set/.


# all three directories need to be cleaned
# the ( cd .... && .... ) lines
# start a new sub shell, 
# cd to the appropriate directory, 
# perform the rm function, 
# and exit the sub shell
# which results in being back in the original directory
clean:
        $(RM) -f *.o $(EXEC1) $(EXEC2) #(EXEC3)
        ( cd my_set && $(RM) -f *.o )
        ( cd tests  && $(RM) -f *.o )