c++的移动构造, 移动赋值, 拷贝构造, 拷贝赋值

 我也算写点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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值