jjzjj

<三>关于对象优化

ericshi1985 2023-03-28 原文

代码1

#include <iostream>
#include <functional>
#include<cstdio>
#include<cstring>


using namespace std; 

class MyString3 {

public:
	MyString3(const char * pChar=nullptr) {
		if (pChar == nullptr) {
			this->pString = new char[1];
			this->pString[0] = '\0';
		
		}
		else {
			int len = strlen(pChar);
			this->pString = new char[len + 1];
			strcpy(this->pString, pChar);
		}	
		cout << "MyString 构造函数 函数地址"<<(int *)this << endl;
	}
	// 左值拷贝构造
	MyString3(const MyString3 & _rval) {

		int len = strlen(_rval.pString);
		this->pString = new char[len + 1];
		strcpy(this->pString, _rval.pString);
		cout << "MyString 左值拷贝构造函数,原对象地址"<<(int *)(&_rval) <<"目标对象地址"<<(int *)(this)  << endl;
	}

	//左值赋值重载函数
	MyString3 & operator =(const MyString3 & _rval) {
		cout << "MyString 左值赋值重载函数,原对象地址"<<(int *)(&_rval) <<"目标对象地址"<<(int *)(this)  << endl;
		if (this == &_rval) { return *this; }
		else {
			
			delete[]this->pString;
			this->pString = nullptr;
			
			int len = strlen(_rval.pString);
			char *tep = new char[len + 1];
			strcpy(tep,_rval.pString);
			this->pString = tep;	
			
			return *this;
		}
		
	}

	const char * c_str() {
		return pString;
	}
	
	~MyString3() {
		cout << "MyString 析构函数,析构函数对象地址"<<(int *)(this) << endl;
		delete[] this->pString;
		pString = nullptr;
	}

private:
	char *pString;

};


MyString3  getMyString(MyString3  & ms) {

	const char * tep = ms.c_str();

	MyString3  S(tep);

	return S;

}

int main() {

	MyString3 S1("ABCDEF123456");
	MyString3 S2;
	S2=getMyString(S1);
       std::cout<<"S2对象地址"<<(int *)(&S2)<<std::endl;
	system("pause");

	return 0;
}

上面出现大量重复的空间开辟和析构过程.

如何解决上面的问题?

先回顾一下以前关于左值引用,和右值引用

int a =10;
int & ra=a;
左值,有名字,有地址 如a ,可以将左值引用绑定到一个左值上

int &b =100;//错误 不能将左值引用绑定到一个右值,100是右值
右值:没有名字,没有地址

int &&rb=100;//ok 将右值引用绑定到 右值

int &&rb=a;//错误,不能将右值引用绑定到左值

int &b =100 //错误, 如果要想可以  需要 const int &b =100; 编译器其实生成了一个 临时量 int tep=100; int &b=tep;


同理
// 不可以,因为C++编译器将匿名对象都看做右值,所以要 MyString3 && rs=MyString3;或者 const MyString3 &s=MyString3;
MyString3 &s=MyString3("ABC");

对于 C++编译器将匿名对象都看做右值,MyString3 &s=MyString3("ABC");
不同的编译器做法不一样,gcc编译器不允许,但是MSVC上可以 如下两张图

代码2

#include <iostream>
#include <functional>
#include<cstdio>
#include<cstring>

using namespace std;

class MyString3 {

public:
	MyString3(const char * pChar=nullptr) {
		if (pChar == nullptr) {
			this->pString = new char[1];
			this->pString[0] = '\0';
		
		}
		else {
			int len = strlen(pChar);
			this->pString = new char[len + 1];
			strcpy(this->pString, pChar);
		}	
		cout << "MyString 构造函数,对象地址"<<(int *)(this) << endl;
	}
	// 左值拷贝构造
	MyString3(const MyString3 & _rval) {

		int len = strlen(_rval.pString);
		this->pString = new char[len + 1];
		strcpy(this->pString, _rval.pString);
		cout << "MyString 左值拷贝构造函数,原对象地址"<<(int *)(&_rval)<<"目标对象地址"<<(int *)(this) << endl;
	}
	// 右值拷贝构造, MyString3 && _rval 这个形参,右值引用 匹配 的是 临时对象
	MyString3(MyString3 && _rval) {
		//由于临时对象声明周期 只在当前语句,出了当前语句就销售了
		//所以我们可以复用他开辟的堆空间,避免重复开辟
		this->pString = _rval.pString;
		_rval.pString = nullptr;//要置空,避免多个MyString 对象指向同一个堆空间
		cout << "MyString 移动构造函数,原对象地址"<<(int*)(&_rval)<<"目标对象地址"<<(int *)(this) << endl;
	}


	//左值赋值重载函数
	MyString3 & operator =(const MyString3 & _rval) {
		cout << "MyString 左值赋值重载函数" << endl;
		if (this == &_rval) { return *this; }
		else {
			
			delete[]this->pString;
			this->pString = nullptr;
			
			int len = strlen(_rval.pString);
			char *tep = new char[len + 1];
			strcpy(tep,_rval.pString);
			this->pString = tep;	
			
			return *this;
		}
		
	}

	//右值赋值重载函数 MyString3 && _rval 这个形参,右值引用 匹配 的是 临时对象
	MyString3 & operator =(MyString3 && _rval) {
		cout << "MyString 移动赋值重载函数,原对象地址"<<(int*)(&_rval)<<"目标对象地址"<<(int *)(this) << endl;
		if (this == &_rval) { return *this; }
		else {
			//由于临时对象声明周期 只在当前语句,出了当前语句就销毁了
			//所以我们可以复用他开辟的堆空间,避免重复开辟
			this->pString = _rval.pString;
			_rval.pString = nullptr;//要置空,避免多个MyString 对象指向同一个堆空间
			return *this;
		}

	}

	const char * c_str() {
		return pString;
	}
	
	~MyString3() {
		cout << "MyString 析构函数,析构对象地址"<<(int *)(this) << endl;
		delete[] this->pString;
		pString = nullptr;
	}

private:
	char *pString;

};


MyString3  getMyString(MyString3  & ms) {

	const char * tep = ms.c_str();

	MyString3  S(tep);

	return S;

}

int main() {

	MyString3 S1("ABCDEF123456");
	MyString3 S2;
	S2=getMyString(S1);

	system("pause");

	return 0;
}


通过右值引用,避免了一些内存重复开辟

代码3

MyString3 operator +(const MyString3 & ls,const  MyString3 rs) {

	char * tp = new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(tp, ls.pString);
	strcat(tp, rs.pString);
	return MyString3(tp);
}


ostream & operator <<(ostream &out, const MyString3 & s) {

	cout << s.c_str() << endl;
	return out;

}


int main() {

	MyString3 S1("ABCDEF");
	MyString3 S2=("1234");
	
	MyString3 S3 = S1 + S2;

	cout << S3 <<"S3地址 ="<<&S3 << endl;

	system("pause");

	return 0;
}

在MyString 中加入 + 法操作,上面的 operator +()函数有问题, tp 没有 delete 内存泄漏了
修改如下

MyString3  operator+ (const MyString3 & ls, const MyString3 & rs) {

	char * tp = new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(tp, ls.pString);
	strcat(tp, rs.pString);

	MyString3  ts(tp);
	delete[]tp;
	cout << " operato + " << endl;
	return ts;
}

//修改完成后 tp 指针能正常释放内存, 但是多构建了MyString3  ts(tp);对象,继续优化,执行结果如下第二张图


MyString3  operator+ (const MyString3 & ls, const MyString3 & rs) {

        MyString3  ts;
	ts.pString= new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(ts.pString, ls.pString);
	strcat(ts.pString, rs.pString);
	cout << " operato + " << endl;
	return ts;
}

MyString3 S3 = S1 + S2;  //operator+ 返回的ts对象会使用 右值拷贝构造创建 S3,避免了像左值拷贝构造一样 一次堆内存的开辟


有关<三>关于对象优化的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  6. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  7. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  8. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  9. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  10. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

随机推荐