我也算写点c++代码的,在这个问题,搞不清楚,因为没看过c++编程宝典之类的丛书,没这个基础。上代码:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <utility>
class Rvalue{
public:
Rvalue():data_{nullptr},len_(0){
i_=ref_;
ref_++;
}
~Rvalue(){
printf("rvalue dtor i %d %d\n",i_,len_);
if(data_){
delete [] data_;
len_=0;
printf("buf delete\n");
}
}
Rvalue(Rvalue &&r){
printf("copy\n");
i_=ref_;
ref_++;
if(r.data_){
len_=r.len_;
data_=r.data_;
r.data_=nullptr;
r.len_=0;
}
}
//https://www.cnblogs.com/xiaobingqianrui/p/9064260.html
Rvalue & operator=(Rvalue &&r){
i_=ref_;
ref_++;
printf("assign\n");
if(r.data_){
len_=r.len_;
data_=r.data_;
r.data_=nullptr;
r.len_=0;
}
return *this;
}
/* annotate this on purpose
Rvalue(const Rvalue &other){
i_=ref_;
ref_++;
data_=nullptr;
len_=0;
}
Rvalue &operator=(const Rvalue &other){
i_=ref_;
ref_++;
data_=nullptr;
len_=0;
return *this;
}*/
void WriteContent(uint8_t*con,uint32_t len){
len_=len;
data_=new uint8_t [len];
memcpy(data_,con,len);
}
void Print(){
if(data_){
printf("%s\n",data_);
}else{
printf("void data\n");
}
}
private:
uint8_t *data_;
uint32_t len_;
uint32_t i_{0};
static uint32_t ref_;
};
uint32_t Rvalue::ref_=0;
void TestRvalue(Rvalue &&r){
printf("landmark\n");
//'constexpr Rvalue::Rvalue(const Rvalue&)' is implicitly declared as deleted because 'Rvalue' declares a move constructor or move assignment operator
Rvalue l=r;
l.Print();
}
void TestRvalue1(Rvalue &&r){
Rvalue l;
l=r;
}
void TestRvalue2(Rvalue &&r){
Rvalue l(std::move(r));
//Rvalue l=std::move(r);
}
void TestRvalue3(Rvalue &&r){
Rvalue l;
l=std::move(r);
}
char content[]="hello world";
int main(){
Rvalue l;
l.WriteContent((uint8_t*)content,strlen(content)+1);
TestRvalue(std::move(l));
printf("after\n");
return 0;
}
因为我注释掉代码中标注“annotate this on purpose”的部分,程序是不能编译通过的。不出现错误,也就不会尝试去理解c++中移动构造, 移动赋值, 拷贝构造, 拷贝赋值的含义。
下面分别说明几个测试函数到底调用了类Rvalue中哪一个构造形式。
void TestRvalue(Rvalue &&r){
//拷贝构造
Rvalue l=r;//Rvalue(const Rvalue &other)
l.Print();
}
void TestRvalue1(Rvalue &&r){
Rvalue l;
//拷贝赋值
l=r; //Rvalue &operator=(const Rvalue &other)
}
void TestRvalue2(Rvalue &&r){
//移动构造
Rvalue l(std::move(r));//Rvalue(Rvalue &&r)
//Rvalue l=std::move(r);//Rvalue(Rvalue &&r)
}
void TestRvalue3(Rvalue &&r){
Rvalue l;
//移动赋值
l=std::move(r);//Rvalue & operator=(Rvalue &&r)
}
我原以为这里(TestRvalue(std::move(l));)的std::move(l)会重新分配一段空间,把l重新构造,转成右值。看来不是这样的,只是一个强制类型转换。
偷,还是不偷,std::move(l)中了l的内容,取决于移动赋值和移动构造的实现。这里的实现,就是偷了。
给个在智能指针中的应用例子,代码大部分参考了webrtc中的scoped_ref_ptr。
refcount.h
#ifndef REF_COUNT_H_
#define REF_COUNT_H_
#include <atomic>
namespace zsy{
enum class RefCountStatus { kLast, kOthers};
class RefCountInterface{
public:
virtual void AddRef() const =0;
virtual RefCountStatus Release() const =0;
protected:
virtual ~RefCountInterface(){}
};
class RefCounter{
public:
RefCounter(int i=0):ref_count_(i){}
void IncRef(){
std::atomic_fetch_add(&ref_count_,1);
}
RefCountStatus DecRef(){
int x=0;
x=std::atomic_fetch_sub(&ref_count_,1);
return (x==1)?RefCountStatus::kLast:RefCountStatus::kOthers;
}
int getValue(){
int x=0;
x=ref_count_.load(std::memory_order_relaxed);
return x;
}
bool HasOneRef(){
int x=0;
x=ref_count_.load(std::memory_order_relaxed);
return x==1;
}
private:
std::atomic<int> ref_count_;
};
template <class T>
class RefObject:public T{
public:
RefObject():ref_count_(0){}
template<class P0>
explicit RefObject(P0&&p0):T(std::forward<P0>(p0)){}
template<class P0,class P1,typename ...Args>
RefObject(P0&&p0,P1&&p1,Args&&...args):T(std::forward<P0>(p0),
std::forward<P1>(p1),
std::forward<Args>(args)...){
}
virtual void AddRef() const{
ref_count_.IncRef();
}
virtual RefCountStatus Release() const{
auto status=ref_count_.DecRef();
if(status==RefCountStatus::kLast){
delete this;
}
return status;
}
virtual bool HasOneRef() { return ref_count_.HasOneRef(); }
protected:
virtual ~RefObject(){}
private:
mutable RefCounter ref_count_;
};
template <class T>
class ScopedRefPtr{
public:
ScopedRefPtr():ptr_(nullptr){}
ScopedRefPtr(T *ptr):ptr_(ptr){
if(ptr_){
ptr_->AddRef();
}
}
ScopedRefPtr(const ScopedRefPtr<T>& r):ptr_(r.ptr_){
if(ptr_){
ptr_->AddRef();
}
}
ScopedRefPtr<T>& operator=(T*p){
if(p){
p->AddRef();
}
if(ptr_){
ptr_->Release();
}
ptr_=p;
return *this;
}
ScopedRefPtr<T>& operator=(const ScopedRefPtr<T>& r){
return *this=r.ptr;
}
ScopedRefPtr(ScopedRefPtr<T>&& r):ptr_(r.release()){}
ScopedRefPtr<T>& operator=(ScopedRefPtr<T>&& r){
ScopedRefPtr<T>(std::move(r)).Swap(*this);
return *this;
}
template <typename U>
ScopedRefPtr(ScopedRefPtr<U>&& r) : ptr_(r.release()) {}
template <typename U>
ScopedRefPtr<T>& operator=(ScopedRefPtr<U>&& r){
ScopedRefPtr<T>(std::move(r)).Swap(*this);
return *this;
}
template <typename U>
ScopedRefPtr<T>& operator=(ScopedRefPtr<U>& r){
return *this=r.get();
}
~ScopedRefPtr(){
if(ptr_){
ptr_->Release();
}
}
T&get()const {
return ptr_;
}
T*release(){
T*ret=ptr_;
ptr_=nullptr;
return ret;
}
operator T*() const { return ptr_; }
T* operator->() const { return ptr_; }
void Swap(T**pp){
T*p=ptr_;
ptr_=*pp;
*pp=p;
}
void Swap(ScopedRefPtr<T>& r){
Swap(&r.ptr_);
}
private:
T* ptr_;
};
template<class T>
class ObjectWrappperCounter{
public:
ObjectWrappperCounter(T*p):ptr_(p){
AddRef();
}
void AddRef(){
ref_count_.IncRef();
}
void Release(){
auto status=ref_count_.DecRef();
if(status==RefCountStatus::kLast){
if(ptr_){
delete ptr_;
}
delete this;
}
}
T* get(){
return ptr_;
}
int getRef(){
return ref_count_.getValue();
}
private:
T* ptr_{nullptr};
RefCounter ref_count_{0};
};
template <class T>
class SharedPtr{
public:
SharedPtr(){}
SharedPtr(T*ptr){
if(!ptr){
wrapper_=nullptr;
}else{
wrapper_=new ObjectWrappperCounter<T>(ptr);
}
}
/*
template<class P0>
SharedPtr(P0 &&p0):wrapper_(new ObjectWrappperCounter<T>(std::forward(p0))){}
template<class P0,class P1,typename ...Args>
SharedPtr(P0 &&p0,P1 &&p1,Args&&...args):wrapper_(
new ObjectWrappperCounter<T>(
std::forward(p0),
std::forward(p1),
std::forward<Args>(args)...)){}*/
SharedPtr<T> & operator=(T*p){
if(p){
p->AddRef();
}
if(wrapper_){
wrapper_->Release();
}
wrapper_=p;
return *this;
}
SharedPtr(SharedPtr<T> &&r):wrapper_(r.release()){}
SharedPtr<T> &operator=(SharedPtr<T> &&r){
SharedPtr<T>(std::move(r)).Swap(*this);
return *this;
}
SharedPtr(const SharedPtr<T> &r):wrapper_(r.wrapper_){
if(wrapper_){
wrapper_->AddRef();
}
}
SharedPtr<T> &operator=(const SharedPtr<T> &r){
return *this=r.wrapper_;
}
~SharedPtr(){
if(wrapper_){
wrapper_->Release();
}
}
void Swap(ObjectWrappperCounter<T>**pp){
ObjectWrappperCounter<T> *p=*pp;
*pp=wrapper_;
wrapper_=p;
}
void Swap(SharedPtr<T> &r){
Swap(&r.wrapper_);
}
T* operator -> (){
return wrapper_->get();
}
ObjectWrappperCounter<T>*release(){
ObjectWrappperCounter<T> *ret=wrapper_;
wrapper_=nullptr;
return ret;
}
int getRefNum(){
int ret=0;
if(wrapper_){
ret=wrapper_->getRef();
}
return ret;
}
private:
ObjectWrappperCounter<T> *wrapper_{nullptr};
};
template<class T>
class WeakPtr{
public:
WeakPtr(){}
WeakPtr(SharedPtr<T>&src){
_ptr_=&src;
}
SharedPtr<T> lock(){
if(_ptr_->getRefNum()){
return *_ptr_;
}else{
return nullptr;
}
}
private:
SharedPtr<T> *_ptr_;
};
}
#endif
测试例子1
#include <iostream>
#include <stdio.h>
#include "refcount.h"
using namespace zsy;
class Parent{
public:
virtual ~Parent(){
printf("parent dtor\n");
}
};
class Child :public Parent,zsy::RefCountInterface{
public:
virtual ~Child(){
printf("child dtor\n");
}
};
void Test2(ScopedRefPtr<RefObject<Child>>&& c){
ScopedRefPtr<RefObject<Child>> child=std::move(c);
}
void Test(){
ScopedRefPtr<RefObject<Child>> c(new RefObject<Child>());
Test2(std::move(c));
}
int main(){
Test();
return 0;
}
使用ScopedRefPtr的类需要继承RefCountInterface这个接口,似乎不是很方便。参考[3]和[4]的博文,模拟实现了shared_ptr和weak_ptr。
#include <iostream>
#include <stdio.h>
#include "refcount.h"
using namespace zsy;
class B;
class A{
public:
~A(){
printf("A dtor\n");
}
WeakPtr<B> b_ptr_;
};
class B{
public:
~B(){
printf("B dtor\n");
}
WeakPtr<A> a_ptr_;
};
void MoveTest(SharedPtr<A> &&a){
SharedPtr<A> l;
l=std::move(a);
printf("l %d\n",l.getRefNum());
}
void MyTest(){
SharedPtr<A> a(new A());
SharedPtr<B> b(new B());
a->b_ptr_=b;
b->a_ptr_=a;
SharedPtr<B> b1=a->b_ptr_.lock();
MoveTest(std::move(a));
printf("a %d\n",a.getRefNum());
printf("b %d\n",b.getRefNum());
}
int main(){
MyTest();
return 0;
}
std::move的操作测试:
#include <deque>
#include <stdint.h>
#include <iostream>
#include <string.h>
#include <string>
struct MemSlice{
MemSlice(){
}
MemSlice(const char*cont,int len){
len_=len;
buf_=(char*)malloc(sizeof(char)*(len+1));
memset(buf_,0,len+1);
memcpy(buf_,cont,len);
}
MemSlice(MemSlice&& r){
this->buf_=r.buf_;
this->len_=r.len_;
r.buf_=NULL;
r.len_=0;
}
~MemSlice(){
printf("delete\n");
if(buf_){
printf("with buffer\n");
free(buf_);
}
}
operator=(const MemSlice &o)=delete;
char *buf_{NULL};
int len_{0};
};
int main(){
std::string content("hello this");
MemSlice slice(content.c_str(),(int)content.size());
std::deque<MemSlice> buffer;
buffer.push_back(std::move(slice));
//可以看看内存释放的前后顺序,帮助理解move操作
/*MemSlice slice2(std::move(buffer.front()));*/
buffer.pop_front();
printf("hello word\n");
}
子类的的move操作传递到父类:
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
class Parent{
public:
Parent(){}
Parent(const Parent&)=default;
Parent(Parent&& r){
*this=std::move(r);
}
Parent& operator=(Parent&& r){
std::cout<<"parent move"<<std::endl;
p_=r.p_;
return *this;
}
Parent& operator=(const Parent&)=default;
~Parent(){}
void SetP(int v){
p_=v;
}
int GetP() const{
return p_;
}
public:
int p_{0};
};
class Child:public Parent{
public:
Child(){}
~Child(){}
Child(const Child &)=default;
Child&operator=(const Child &)=default;
Child(Child &&r):Parent(std::move(r)){
}
Child&operator=(Child &&r){
*static_cast<Parent*>(this)=std::move(r);
std::cout<<"child move"<<std::endl;
c_=r.c_;
return *this;
}
public:
int c_{0};
};
int main(){
Child c;
c.p_=2;
c.c_=2;
Child c1=std::move(c);
std::cout<<c1.p_<<std::endl;
return 0;
}
以上代码并没有什么实际用途,权当是对c++的练习了。
[1] 现代c++之移动构造, 移动赋值, 拷贝构造, 拷贝赋值 https://blog.csdn.net/chenhaifeng2016/article/details/74192525
[2] C++学习笔记之模版 remove_reference(引用移除) https://www.cnblogs.com/creativityroom/p/6891772.html
[3] 模拟实现boost库中的shared_ptr https://blog.csdn.net/qq_41822235/article/details/82934681
[4] 模拟实现boost库中的weak_ptr https://blog.csdn.net/qq_41822235/article/details/82936615