测试string类作栈内对象返回时其gcc和VC6.0编译器的处理方式,以及测试move操作

/*
1.gcc编译运行结果
[root@VM_0_7_centos test]# g++ --std=c++17  mystring.cpp 
[root@VM_0_7_centos test]# ./a.out  1
String ctor: null
String ctor: two
String ctor: three
String copy ctor: two
a.c_str() = 
b.c_str() = two
d.c_str() = three
e.c_str() = two
ctor_cnt1= 4
String ctor: one
String move ctor: one
String dtor: null
------------
String copy ctor: one
ctor_cnt2= 6
String copy ctor: two
ctor_cnt3= 7
String move ctor: two
ctor_cnt4= 7
String operator= : two
ctor_cnt5= 7
a.c_str() = two
b.c_str() = two
d.c_str() = three
---String g(std::move(a))---
String ctor: null
String move ctor: two
g.c_str() = two
String dtor: two
it.c_str() = one
it.c_str() = two
After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"
String dtor: one
String dtor: two
String dtor: null
String dtor: three
String dtor: two
String dtor: null
ctor_cnt= 8
dtor_cnt= 8



2.VC6.0 运行结果
String ctor: null
String ctor: two
String ctor: three
String copy ctor: three
String dtor: three
String copy ctor: two
a.c_str() =
b.c_str() = two
d.c_str() = three
e.c_str() = two
String dtor: two
String dtor: three
String dtor: two
String dtor:
ctor_cnt= 5
dtor_cnt= 5
Press any key to continue

结论:gcc 默认会开启rov优化,有些可以不用进行拷贝构造函数提高效率

*/

#include <iostream>
#include <string.h>
#include <vector>

using namespace std;

int ctor_cnt = 0;
int dtor_cnt = 0;
bool ismove = 0;

class String{
    public:
        friend ostream& operator<< (ostream&,String&);//重载<<运算符  
        friend istream& operator>> (istream&,String&);//重载>>运算符  
    
        String(const char* ptr = NULL); //通配构造函数
        String(const String& str); //拷贝构造函数
		String& operator=(const String & str);//=运算符重载
		#ifdef __GNUC__
		String& operator=(String&& other);
		#endif
        size_t size() const; //获取字符的长度
        const char* c_str();//转化成c字符串
        ~String(); //析构函数
    //private:
    public:
        char* data;     //实际字符串内容
        size_t length;  //字符串的长度
};

//重载输出运算符
ostream& operator<< (ostream& os,String& str)//重载<<运算符  
{
    os<<str.data;
    return os;
}


//重载输入运算符
istream& operator>> (istream& is ,String& str)//重载>>运算符  
{
    该用法是错误的is>>str.data;
    //因为不能确定str.data和输入的字符串的大小
    char tmp[1000] = {0};
    is>>tmp;
    str.length = strlen(tmp);
    str.data = new char[str.length + 1];
    strcpy(str.data,tmp);
    return is;
    
}



//通用构造函数
String::String(const char* ptr){

    if(!ptr){
        
        data = new char[1];
        *data = 0;
        length = 0;
		cout<<"String ctor: null"<<endl;
    }else{
        length = strlen(ptr);
        data = new char[length + 1];
        strcpy(data,ptr);
		cout<<"String ctor: "<<ptr<<endl;
    }
    
	ctor_cnt++;
}


//拷贝构造函数,需要进行深拷贝
//使用方法:String s2(s1); 使用s1来初始化s2,调用该拷贝构造函数进行深拷贝
String::String(const String& str)
{
    if(!str.data){
        data = 0;
    }else{
        length = strlen(str.data);
        data = new char[length + 1];
        strcpy(data,str.data);
		data[length] = 0;
    }

	ctor_cnt++;
	cout<<"String copy ctor: "<<data<<endl;
}


String& String::operator=(const String &str)//赋值操作符4步
{
    if (this == &str) return *this;//1 自我赋值,返回自身引用

    delete[] data;//2 删除原有数据
    
    length = str.size();//3 深拷贝
    data = new char[length + 1];
    strcpy(data, str.data);

	cout<<"String operator= : "<<data<<endl;
    return *this;//4 返回自身引用
}

size_t String::size() const//获取字符的长度
{
    return length;
}

const char* String::c_str()//转化成c字符串
{
    return data;
}


String::~String() //析构函数
{
    if(data){
		cout<<"String dtor: "<<data<<endl;
        delete []data;
        data = NULL;
        length = 0;
    }
	else
	{
		cout<<"String dtor: null"<<endl;
	}
    
    dtor_cnt++;
}

#ifdef __GNUC__
// 简单的移动赋值运算符
String& String::operator=(String&& other)
{
     if (other.data)
     {
         data = std::move(other.data);
         length = std::move(other.length);
         
         other.data = 0;
         other.length = 0;
     }
     
     cout<<"String move ctor: "<<data<<endl;
     return *this;
     
}
#endif

//gcc 默认会进行rov优化,不会调用拷贝构造函数,直接把栈内的f对象提升级调用函数可用对象,避免调用拷贝构造函数及销毁栈内的c对象的效率降低操作
String make_string()
{
    String c("three");//gcc-3  VC-3 按基本原理 c对象在make_string退出时就会销毁
    return c;//gcc-3  VC-4 这个会发生拷贝构造函数,深度拷贝 
}


int test_fun()
{
	String a;//gcc-1  VC-1
	String b("two");//gcc-2  VC-2
	String d = make_string();//gcc-3  VC-4不是返回c对象,而是返回对c对象的拷贝  gcc与VC编译器有没有rov优化主要差别在这句

    String e = b;//gcc-4  VC-5
    
    
	cout <<"a.c_str() = "<<a.c_str()<<endl;
	cout <<"b.c_str() = "<<b.c_str()<<endl;
	cout <<"d.c_str() = "<<d.c_str()<<endl;
	cout <<"e.c_str() = "<<e.c_str()<<endl;
    
    
        
    #ifdef __GNUC__
    cout<<"ctor_cnt1= "<<ctor_cnt<<endl;
    std::vector<String> v2;
    v2.reserve(16);//先预分配16个,不然空间不够时,会重新分配和移动原空间,如由1-》2会发生2次拷贝构造函数
    
    a = "one";//这一步会先用创建“one”创建一个临时对象,然后再运行String& String::operator=(String&& other)进行move操作,最后再销毁临时对象
    cout<<"------------"<<endl;
    v2.push_back(a);//会调用拷贝构造函数
   
    cout<<"ctor_cnt2= "<<ctor_cnt<<endl;
    v2.push_back(b);//调用拷贝构造函数  没有v2.reserve(16);这句时,由1——》2会发生2次拷贝构造函数  vector一般每次以2幂次增长  
    cout<<"ctor_cnt3= "<<ctor_cnt<<endl;    
    a=std::move(e);//调用String& String::operator=(String&& other)进行move操作,操作完,e的指针为变成空,这行与a = e;是不一样的
    cout<<"ctor_cnt4= "<<ctor_cnt<<endl;     
    b = a; //调用 String& String::operator=(const String &str)进行赋值操作
    cout<<"ctor_cnt5= "<<ctor_cnt<<endl;    
    cout <<"a.c_str() = "<<a.c_str()<<endl;
    cout <<"b.c_str() = "<<b.c_str()<<endl;
    cout <<"d.c_str() = "<<d.c_str()<<endl;
    if (e.c_str())//这个不会打印出来,因为使用了a=std::move(e);会调用String& String::operator=(String&& other)
    {
        cout <<"e.c_str() = "<<e.c_str()<<endl;
    }
    
    std::vector<String> v3;

    if (ismove)
    {
        v3 = std::move(v2);//与v3 = v2;是有差异的,这个是不是创建新的String类,只是把v2中移到v3
    }
    else
    {
        v3 = v2;
    }
    
    
    if(ismove)
    {
        cout<<"---String g(std::move(a))---"<<endl;
        String g;
        g  = std::move(a);
            
        if (a.c_str())//这个不会打印出来,因为使用了a=std::move(e);会调用String& String::operator=(String&& other)
        {
            cout <<"a.c_str() = "<<a.c_str()<<endl;
        }
        if (g.c_str())
        {
            cout <<"g.c_str() = "<<g.c_str()<<endl;
        }
    }
    else
    {
        cout<<"---String g(a)---"<<endl;
        //String g(a);//-->String copy ctor: two
        String g(std::move(a));//-->String copy ctor: two  这个不会进行move操作,与String g(a)结果一样,编译器优化掉?
        
        if (a.c_str())
        {
            cout <<"a.c_str() = "<<a.c_str()<<endl;
        }
        if (g.c_str())
        {
            cout <<"g.c_str() = "<<g.c_str()<<endl;
        }
    }
    
    
    
    for (std::vector<String>::iterator it=v3.begin(); it!=v3.end();++it)
    {
        cout <<"it.c_str() = "<<it->c_str()<<endl;
    }
     
    #endif  
    

    #ifdef __GNUC__
    std::string str = "Hello";
    std::vector<std::string> v;
 
    // 使用 push_back(const T&) 重载,
    // 表示我们将带来复制 str 的成本
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
 
    // 使用右值引用 push_back(T&&) 重载,
    // 表示不复制字符串;而是
    // str 的内容被移动进 vector
    // 这个开销比较低,但也意味着 str 现在可能为空。
    // 若是这个对象后面就不再使用,如当前这种情况,可使用std::move(cb)这种方式,这种方式只会调整指针,不过通过这种操作str对象后面就不能再使用了
    /*
    //C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了,通过std::move,可以避免不必要的拷贝操作。
    //std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
    //对指针类型的标准库对象并不需要这么做.
    */
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
 
    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
    #endif
                  
	
	return 0;
}

int main(int argc,char **argv)
{
    if (argc > 1)
    {
        ismove = bool(atoi(argv[1])&0x01);
    }
    
    
    
    test_fun();
    
    cout<<"ctor_cnt= "<<ctor_cnt<<endl;
    cout<<"dtor_cnt= "<<dtor_cnt<<endl;
    
    return 0;
}

/*
#include <iostream>
#include <string>
using namespace std;

class String
{
public:
    String(const char* str = NULL);//通用构造函数,String("abc")
    String(const String &str);//拷贝构造
    ~String();

    String& operator=(const String &str);//赋值运算符。返回引用
    String operator+(const String &str) const;
    String& operator+=(const String &str);//+=操作符。返回引用
    char& operator[](int n) const;//下标操作符。返回引用
    bool operator==(const String &str) const;

    int size() const;//字符串实际大小,不包括结束符
    const char *c_str() const;//将string转为char *

private:
    char *data;
    int length;
};

String::String(const char* str)//通用构造
{
    if (!str)
    {//为空。String a()
        length = 0;
        data = new char[1];
        *data = '\0';
    }
    else
    {
        length = strlen(str);
        data = new char[length + 1];
        strcpy(data, str);//会拷贝源的结束符
    }
}


String::String(const String &str)//拷贝构造,深拷贝
{
    length = str.size();
    data = new char[length + 1];
    strcpy(data, str.c_str());
}

String::~String()
{
    delete[] data;
    length = 0;
}

String& String::operator=(const String &str)//赋值操作符4步
{
    if (this == &str) return *this;//1 自我赋值,返回自身引用

    delete[] data;//2 删除原有数据
    
    length = str.size();//3 深拷贝
    data = new char[length + 1];
    strcpy(data, str.c_str());

    return *this;//4 返回自身引用
}
String String::operator+(const String &str) const//+操作符3步
{//新建对象包括新空间,拷贝两个数据,返回新空间
    String newString;
    newString.length = length + str.size();
    newString.data = new char[newString.length + 1];
    strcpy(newString.data, data);
    strcat(newString.data, str.data);
    return newString;
}

String& String::operator+=(const String &str)//+=操作符5步
{//重分配新空间,拷贝两个数据,删除自己原空间,赋值为新空间,返回引用
    length += str.size();//成员length是实际长度
    char *newdata = new char[length + 1];
    strcpy(newdata, data);
    strcat(newdata, str.c_str());
    delete[] data;
    data = newdata;
    return *this;
}

char& String::operator[](int n) const
{//下标操作符,返回引用
    if (n >= length) return data[length - 1];//如果越界,返回最后一个字符
    else return data[n];
}

bool String::operator==(const String &str) const
{
    if (length != str.size()) return false;
    return strcmp(data, str.c_str())   false : true;
}

int String::size() const
{
    return length;
}

const char *String::c_str() const
{
    return data;
}

int main()
{
    char a[] = "Hello", b[] = "World!";
    String s1(a), s2(b);
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    s1 += s2;
    cout << s1.c_str() << endl;
    s1 = s2;
    cout << s1.c_str() << endl;
    cout << (s1 + s2).c_str() << endl;
    cout << s1.size() << endl;
    cout << s1[1] << endl;

    if (s1 == s2)
        cout << "相等" << endl;
        
	return 0;
}
*/

/*

//std::move使用示例
//C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了,通过std::move,可以避免不必要的拷贝操作。
//std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
//对指针类型的标准库对象并不需要这么做.


#include <iostream>
#include <utility>
#include <vector>
#include <string>
 
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;
 
    // 使用 push_back(const T&) 重载,
    // 表示我们将带来复制 str 的成本
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
 
    // 使用右值引用 push_back(T&&) 重载,
    // 表示不复制字符串;而是
    // str 的内容被移动进 vector
    // 这个开销比较低,但也意味着 str 现在可能为空。
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
 
    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值