C++移动语义构造实验

实验目的

1. 验证左值与右值的区别;验证右值引用的使用;

2. 设计并验证移动构造函数和移动复制函数的定义与使用,及其带来的效率提升;

实验内容 

1. 参考std::string,设计并实现MyString类。

基本功能要求:

1)四种构造函数、析构函数;

2)重载赋值操作符=,使其正确完成String类型的赋值操作
3)重载必要的操作符实现形如 String a = Hello ; a += World!;的功能。

4)重载必要的操作符实现形如 String a, b, c;  c = a + b; 的操作过程。

5)重载必要的操作符当完成 
    String a(Hello );
    a << world;
   的操作过程后,a所代表的字符串为Hello world

6)重载必要的操作符当完成
   String a(test);
   std::cout << a; 的操作过程后在屏幕上输入 test

7)重载必要的操作符当完成
   String a(test);
   a[2] = S; ,a所代表的字符串为teSt

设计及性能要求:

尽可能的高效实现上述MyString类。要给出关于设计思想的描述或是对设计过程做出必要说明和解释。

2.编写相应的测试用例,验证上述功能(包括内存使用的正确性)。

3.编写相应的测试用例,验证移动语义带来的效率提升,并给出分析与解释。

实验过程

MyString.h:

//
// Created by HASEE on 2022/5/30.
//

#ifndef UNTITLED_TEST_1_H
#define UNTITLED_TEST_1_H

using namespace std;
class MyString{
private:
    char *data; // 指向数组首地址
    int len;
public:
    MyString();
    MyString(const char *const);
    MyString(const MyString &a);
    MyString(MyString&& mstr)   noexcept ;
    ~MyString();

//重载<<运算符
MyString & operator <<(const char *);
friend ostream & operator <<(ostream &out,const MyString &s);
//重载=运算符
MyString & operator=( char *str);
MyString & operator=(const MyString &s);
//重载+ +=运算符
MyString & operator +( char *str);
MyString & operator +(const MyString &s);
MyString & operator +=( char *str);
MyString & operator +=(const MyString &s);
//重载[]
char & operator [](int i);
};
#endif //UNTITLED_TEST_1_H

MyString.cpp

//
// Created by HASEE on 2022/5/30.
//

#include <iostream>
#include "MyString.h"
#include <cstring>
#include <cassert>
using namespace std;

MyString::MyString() {//构造空字符串
    data =new char[1];
    data[0]='\0';
    len=0;
}
MyString::MyString(const char *const p) //按照动态指针来构造相应字符串
{
    if(p){
        len= strlen(p); //取长度
        data =new char[len+1];//开辟空间
        strcpy(data,p);//复制值
    } else{
        MyString(); //如果传入的字符串为空,则直接调用缺省值构造函数
    }
    printf("constructor\n");
}
MyString::MyString(const MyString& otherMyString) {//拷贝构造函数,这里的形参使用了const,该形参类中的所有函数都要使用const来修饰
    len=otherMyString.len;
    data=new char[len+1]; //重新开辟空间
    strcpy(data,otherMyString.data);
    printf("copy constructor\n");
}
MyString::~MyString() {
    delete[] data;
}
MyString::MyString(MyString&& mstr) noexcept  {
    if (&mstr == this){
        printf("move constructor\n");
        return ;
    }
    len=mstr.len;
    data=mstr.data;
    printf("move constructor\n");
}

ostream & operator << (ostream &out, const MyString &s) {
    out << s.data;
    return out;
}

MyString &MyString::operator=(char *str) {
    delete[] data;
    len= strlen(str);
    data=new char[len+1];
    strcpy(data,str);
    return *this;
}

MyString &MyString::operator=(const MyString &s) {
    if(&s ==this){//如果自己赋值给自己
        return *this;
    }
    delete[] data; //释放原有内存
    len=s.len;
    data=new char[len+1];
    strcpy(data,s.data);
    return *this ;
}
MyString &MyString::operator+(char *str) {
    char *t=data;//记录this.data
    len=len+ strlen(str);
    data=new char [len+1];
    strcpy(data,t);
    strcat(data,str);//将src的字符串追加到dest结尾
    delete[] t; //内存释放
    return *this ;
}

MyString &MyString::operator+(const MyString &s) {
    char *t=data;
    len=len+s.len;
    data=new char [len+1];
    strcpy(data,t);
    strcat(data,s.data);
    delete[] t; //内存释放
    return *this;
}

MyString & MyString::operator+=(char *str) {
    char *t = data;
    len=len+ strlen(str);
    data=new char[len+1];
    strcpy(data,t);
    strcat(data,str);
    delete[] t;
    return *this;
}

MyString & MyString::operator+=(const MyString &s) {
    char *t = data;
    len=len+s.len;
    data=new char[len+1];
    strcpy(data,t);
    strcat(data,s.data);
    delete[] t;
    return *this;
}

MyString &MyString::operator<<(const char *s) {
    return *this+s;
}

char &MyString::operator[](int i) {
    assert(i >=0&&i<=len); //界限判断
    return *(data+i);
}
MyString foo() {
    return MyString{"woooohooooo"};
}

测试:

int main() {
    printf("+=:");
    MyString s="Hello";
    s+="World!";
    cout<<s<<endl;
    printf("a+b:");
    MyString d="Nihao";
    MyString f="Ni";
    MyString g="hao";
    cout<<f+g<<endl;
    printf("a << world:");
    MyString a("hello");
    a << "world";
    cout<<a<<endl;
    printf("std::cout:");
    MyString b("test");
    std::cout << b;
    printf("\n[]重载:");
    MyString c("test");
    c[2]= 'S';
    cout<<c;
}

测试结果:

 测试二 移动语义带来的效率提升

有移动语义:

void time(){
    auto start=std::chrono::steady_clock::now();
    for(int i=0;i<1000000;++i){
        MyString str =foo();
    }
    auto end=std::chrono::steady_clock::now();
    auto duration =static_cast<std::chrono::duration<double,std::ratio<1,1000>>>(end-start);
    std::cout<<"time is"<<duration.count() <<"ms";
}
int main() {
    time();
}

 结果:

没有移动语义:

 原因:当要复制的对象是一个右值,会调用移动构造函数,其它情况调用复制构造函数。移动构造函数的参数没有使用关键字,参数的变量名前有两个&符号,用来表示右值引用。因为是右值引用,我们可以认为在之后它不会再被使用,所以移动构造函数直接复制了对象数据的内存指针,没有进行内存分配和数据的深copy。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值