今天抽时间学习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 时则会延长了对象的生命期,需要手动将对象从容器中删除,否则对象不会被析构而造成内存泄漏。