参考文章https://cloud.github.com/downloads/chenshuo/documents/CppPractice.pdf
值语义 (value sematics) 指的是对象的拷贝与原对象无关,就像拷贝 int 一样。 C++ 的内置类型 (bool/int/double/char) 都是值语义,标准库里的 complex<> 、 pair<>、vector<>、map<>、string 等等类型也都是值语意,拷贝之后就与原对象脱 离关系。
什么值语义
值语义指的是对象的拷贝和原对象无关(比如深拷贝)
什么事对象语义
就是拷贝后也不能让原来的对象能够复制一份,举个例子,我们拷贝一个TCP的连接的对象,也并没有让系统中这个连接+1。再比如拷贝一个employee对象,就算拷贝了,也不能够在系统中增加一个雇员对象。再比如拷贝muduo库里面的Thread,即便拷贝了一个thread,也并没让系统中的增加了一个一模一样的线程。所以,在对象语义下面,值拷贝不被允许(反正拷贝了也是没有意义的)。
主要出现weak_ptr的原因是解决循环引用的问题
循环引用会出现什么问题呢?
比如下面这个程序:
class Parent;
class Child {
public :
shared_ptr<Parent> parent_ptr_;
~Child(){
cout<<"~child"<<endl;
}
};
class Parent{
public :
shared_ptr<Child > child_ptr_;
~Parent(){
cout<<"~parent"<<endl;
}
};
int main()
{
shared_ptr<Parent > p_ptr(new Parent());
shared_ptr<Child > c_ptr (new Child());
p_ptr->child_ptr_ = c_ptr;
c_ptr->parent_ptr_ = p_ptr;
}
在程序没有退出的时候,Parent和child的引用计数都是2,当程序退出的时候,根据先构造后析构的原则,c_ptr先析构,Child的引用计数是1,p_ptr析构了,导致了Parent的对象上面的引用计数是1(shared_ptr析构引用计数-1)。所以程序退出的时候,引用计数还是1。大家的都还没有析构。
比如parent拥有孩子,爸爸的配偶是妈妈,妈妈的配偶是爸爸(当然),孩子的爸妈是= =。那么在代码里面是怎么实现的呢。
一般是
class Parent;
typedef boost::shared_ptr<Parent> ParentPtr;
class Child : boost::noncopyable
{
public:
explicit Child(const ParentPtr& myMom_,
const ParentPtr& myDad_)
: myMom(myMom_),
myDad(myDad_)
{
}
private:
boost::weak_ptr<Parent> myMom;
boost::weak_ptr<Parent> myDad;
};
typedef boost::shared_ptr<Child> ChildPtr;
class Parent : boost::noncopyable
{
public:
Parent()
{
}
void setSpouser(const ParentPtr& spouser)
{
mySpouser = spouser;
}
void addChild(const ChildPtr& child)
{
myChildren.push_back(child);
}
private:
boost::weak_ptr<Parent> mySpouser;
std::vector<ChildPtr> myChildren;
};
int main()
{
ParentPtr mom(new Parent);
ParentPtr dad(new Parent);
mom->setSpouser(dad);
dad->setSpouser(mom);
{
ChildPtr child(new Child(mom, dad));
mom->addChild(child);
dad->addChild(child);
}
{
ChildPtr child(new Child(mom, dad));
mom->addChild(child);
dad->addChild(child);
}
}
值语义 (value sematics) 指的是对象的拷贝与原对象无关,就像拷贝 int 一样。 C++ 的内置类型 (bool/int/double/char) 都是值语义,标准库里的 complex<> 、 pair<>、vector<>、map<>、string 等等类型也都是值语意,拷贝之后就与原对象脱 离关系。
什么值语义
值语义指的是对象的拷贝和原对象无关(比如深拷贝)
什么事对象语义
就是拷贝后也不能让原来的对象能够复制一份,举个例子,我们拷贝一个TCP的连接的对象,也并没有让系统中这个连接+1。再比如拷贝一个employee对象,就算拷贝了,也不能够在系统中增加一个雇员对象。再比如拷贝muduo库里面的Thread,即便拷贝了一个thread,也并没让系统中的增加了一个一模一样的线程。所以,在对象语义下面,值拷贝不被允许(反正拷贝了也是没有意义的)。
主要出现weak_ptr的原因是解决循环引用的问题
循环引用会出现什么问题呢?
比如下面这个程序:
class Parent;
class Child {
public :
shared_ptr<Parent> parent_ptr_;
~Child(){
cout<<"~child"<<endl;
}
};
class Parent{
public :
shared_ptr<Child > child_ptr_;
~Parent(){
cout<<"~parent"<<endl;
}
};
int main()
{
shared_ptr<Parent > p_ptr(new Parent());
shared_ptr<Child > c_ptr (new Child());
p_ptr->child_ptr_ = c_ptr;
c_ptr->parent_ptr_ = p_ptr;
}
在程序没有退出的时候,Parent和child的引用计数都是2,当程序退出的时候,根据先构造后析构的原则,c_ptr先析构,Child的引用计数是1,p_ptr析构了,导致了Parent的对象上面的引用计数是1(shared_ptr析构引用计数-1)。所以程序退出的时候,引用计数还是1。大家的都还没有析构。
比如parent拥有孩子,爸爸的配偶是妈妈,妈妈的配偶是爸爸(当然),孩子的爸妈是= =。那么在代码里面是怎么实现的呢。
一般是
class Parent;
typedef boost::shared_ptr<Parent> ParentPtr;
class Child : boost::noncopyable
{
public:
explicit Child(const ParentPtr& myMom_,
const ParentPtr& myDad_)
: myMom(myMom_),
myDad(myDad_)
{
}
private:
boost::weak_ptr<Parent> myMom;
boost::weak_ptr<Parent> myDad;
};
typedef boost::shared_ptr<Child> ChildPtr;
class Parent : boost::noncopyable
{
public:
Parent()
{
}
void setSpouser(const ParentPtr& spouser)
{
mySpouser = spouser;
}
void addChild(const ChildPtr& child)
{
myChildren.push_back(child);
}
private:
boost::weak_ptr<Parent> mySpouser;
std::vector<ChildPtr> myChildren;
};
int main()
{
ParentPtr mom(new Parent);
ParentPtr dad(new Parent);
mom->setSpouser(dad);
dad->setSpouser(mom);
{
ChildPtr child(new Child(mom, dad));
mom->addChild(child);
dad->addChild(child);
}
{
ChildPtr child(new Child(mom, dad));
mom->addChild(child);
dad->addChild(child);
}
}