muduo 库的 Observer例子

        今天抽时间学习muduo库,亲手敲下了如下的代码,是可以正常编译运行的代码。

observer_safe.h 声明文件:

#include <vector>
#include <memory>
#include "guard.h"

class Observer
{
public:
	virtual ~Observer() {
		
	}
	virtual void update() = 0;
};

class configObserver: public Observer
{
public:
	configObserver();
	~configObserver();
	virtual void update();
};

class Observable
{
public:
	void obRegister(std::weak_ptr<Observer> x);
	// void unregister(Observer *x); //不需要了

	void notifyObservers();
private:
	CMutex	mMtx;

	//容器中保存的是weak_ptr,能探测对象是否还存在
	std::vector<std::weak_ptr<Observer> > mObserverVect;

	typedef std::vector<std::weak_ptr<Observer> >::iterator Iterator;
};

这个声明中用到 CMutex 类,所以关于 CMutex 类声明文件 mutex.h:

#ifndef __H_MUTEX_H__
#define __H_MUTEX_H__

struct mutexInternal;
class CMutex
{
    CMutex(const CMutex &);
    CMutex& operator=(const CMutex &);

public:
    CMutex();
    ~CMutex();

    /**
     * brief 进入临界区
     * 
    */
    bool enter();

    /**
     * 尝试进入临界区
    */
    bool tryEnter();

    /**
     * 离开临界区
    */
    bool leave();

private:
    mutexInternal *mInternal;
};
#endif

这个只是声明文件,其cpp实现文件 mutex.cpp

#include "mutex.h"
#include <assert.h>
#include <pthread.h>

struct mutexInternal
{
    pthread_mutex_t mtx;
};

CMutex::CMutex()
{
    mInternal = new mutexInternal;
    int rt = pthread_mutex_init(&mInternal->mtx, nullptr);
    assert(rt == 0);
}

CMutex::~CMutex()
{
    int rt = pthread_mutex_destroy(&mInternal->mtx);
    assert(rt == 0);
    delete mInternal;
    mInternal = nullptr;
}

bool CMutex::enter()
{
    return (pthread_mutex_lock(&mInternal->mtx) == 0);
}

bool CMutex::leave()
{
    return (pthread_mutex_unlock(&mInternal->mtx) == 0);
}

bool CMutex::tryEnter()
{
    return (pthread_mutex_trylock(&mInternal->mtx) == 0);
}

main 函数所在的文件,其中包含了 observer_safe.h 声明的类的实现:

#include <stdio.h>
#include <stdlib.h>
#include "observer_safe.h"

configObserver::configObserver()
{

}

configObserver::~configObserver()
{

}

void configObserver::update()
{
	printf("derived configObserver\n");
}

void Observable::obRegister(std::weak_ptr<Observer> x)
{
	CGuard guard(mMtx);
	mObserverVect.push_back(x);
}

void Observable::notifyObservers()
{
	CGuard guard(mMtx);
	Iterator ite = mObserverVect.begin();
	while (ite != mObserverVect.end())
	{
		// weak_ptr 不能单独使用,需要提升为 shared_ptr 后才能使用
		std::shared_ptr<Observer> obj(ite->lock());
		if(obj)
		{	
			printf("reference: %u\n", obj.use_count());
			obj->update();
			++ite;
		}
		else 
		{
			//对象已经销毁,从容器中删除掉 weak_ptr
			ite = mObserverVect.erase(ite);
		}
	}
}

int main()
{
	std::shared_ptr<configObserver> cfgOb(new configObserver);
	Observable obMgr;
	obMgr.obRegister(cfgOb);
	printf("reference: %u\n", cfgOb.use_count());
	obMgr.notifyObservers();

	return 0;
}

Makefile 文件:

#中间文件存放目录,如.o 和 .d 文件

COMPILE_DIR = compile
BIN_DIR = bin


# 可编译arm版本
#CROSS = arm-himix200-linux-
CC = $(CROSS)g++ -std=c++11
CFLAGS = -Werror -g
INCLUDE = -I./include
LIB = -lpthread
SRCS = $(wildcard *.cpp)
#SRCS = $(shell ls -t | grep "\.cpp$$" | head -1)
OBJS = $(patsubst %.cpp, $(COMPILE_DIR)/%.o, $(SRCS))
DEP = $(patsubst %.cpp, $(COMPILE_DIR)/%.cpp.d, $(SRCS))


$(shell if [ ! -d $(COMPILE_DIR) ]; then mkdir $(COMPILE_DIR); fi)
$(shell if [ ! -d $(BIN_DIR) ]; then mkdir $(BIN_DIR); fi)


BIN =
ifeq ($(target), ) #如果是空的
BIN = a.out
else
BIN := $(target)
endif


TARGET=$(BIN_DIR)/$(BIN)


all: $(TARGET)

-include $(DEP)

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) $(INCLUDE) $^ -o $@ $(LIB)


$(COMPILE_DIR)/%.o: %.cpp $(COMPILE_DIR)/%.cpp.d
	$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@

$(COMPILE_DIR)/%.cpp.d: %.cpp
	$(CC) $(CFLAGS) $(INCLUDE) -MM -E -c $< -o $@
	@sed 's/.*\.o/$(subst /,\/,$(dir $@))&/g' $@ > $@.tmp
	@mv $@.tmp $@


.PHONY: clean
clean:
	rm -rf $(COMPILE_DIR) $(BIN_DIR)

代码中添加了两行打印引用计数的语句:

1, 第一行在 obMgr.obRegister(cfgOb); 语句之后打印,此时cfgOb的引用计数是 1,为什么呢?因为 obRegister() 的参数是 weak_ptr<>,将其 push_back 到 vector 中,引用计数是不会增加的,所以还是 1(std::shared_ptr<configObserver> cfgOb(new configObserver); 创建对象时,其引用计数为 1)。

2,第二行在 std::shared_ptr<Observer> obj(ite->lock()); 语句之后打印,此时 obj 的引用计数为2

如文件中所提问:

这里打印出来的引用计数为 2,为什么?因为创建时为 1, 这里 obj 又指向了这个资源,所以引用计数为 2 了。那如果:

即把原来的 weak_ptr 都改成 shared_ptr , observer_safe.h

#include <vector>
#include <memory>
#include "guard.h"

class Observer
{
public:
	virtual ~Observer() {
		
	}
	virtual void update() = 0;
};

class configObserver: public Observer
{
public:
	configObserver();
	~configObserver();
	virtual void update();
};

class Observable
{
public:
	void obRegister(std::shared_ptr<Observer> x);
	// void unregister(Observer *x); //不需要了

	void notifyObservers();
private:
	CMutex	mMtx;

	std::vector<std::shared_ptr<Observer> > mObserverVect;

	typedef std::vector<std::shared_ptr<Observer> >::iterator Iterator;
};

 observer.cpp

#include <stdio.h>
#include <stdlib.h>
#include "observer_safe.h"

configObserver::configObserver()
{

}

configObserver::~configObserver()
{

}

void configObserver::update()
{
	printf("derived configObserver\n");
}

void Observable::obRegister(std::shared_ptr<Observer> x)
{
	CGuard guard(mMtx);
	mObserverVect.push_back(x);
}

void Observable::notifyObservers()
{
	CGuard guard(mMtx);
	Iterator ite = mObserverVect.begin();
	while (ite != mObserverVect.end())
	{
		printf("2, reference count: %u\n", ite->use_count());
		(*ite)->update();
		++ite;
	}
}

int main()
{
	std::shared_ptr<configObserver> cfgOb(new configObserver);
	Observable obMgr;
	obMgr.obRegister(cfgOb);
	printf("1, reference count: %u\n", cfgOb.use_count());
	obMgr.notifyObservers();

	return 0;
}

 代码里同样添加了两处打印,其执行结果为:

结果都是 2,在创建的时候引用计数为 1, 在 push_back 到容器中时引用计数加 1,所以为 2。而用 weak_ptr 类型时则 push_back 到vector时引用计数是不会增加的,所以用 shared_ptr 时则会延长了对象的生命期,需要手动将对象从容器中删除,否则对象不会被析构而造成内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值