C++按值和按址传递对象的思考和优化
C++是一门面向对象(OOP)编程语言,在这门语言中也有函数,函数的参数可以是变量数值,当然也可以是对象。所以,传统地就有关于对象是按值传递还是按址传递的讨论。
在C语言中,按值传递在很多情况下可以出色地完成任务,而且也很好理解,但是在C++中,因为有了类的对象这个可能的庞然大物(指他的数据特别大),如果还用传值的方式进行的话,会很浪费内存空间。本文就具体讨论这个问题。
在C++中,将一个对象按值传递时,会默认调用一个复制构造函数做一个这个参数的副本给函数。默认的复制构造函数名字是:类名(类名&)。请看下面代码:
#include <iostream>
using namespace std; class A
{
public:
A()
{
cout << "执行构造函数" << endl;
}
A(A&)
{
cout << "执行复制构造函数" << endl;
}
~A()
{
cout << "执行析构函数" << endl;
}
}; A func(A one)
{
return one;
}
int main (void)
{
A a;
func(a); return 0;
}
这里的执行结果是:
这里我们发现执行了一次构造函数,两次复制构造函数,三次析构函数,结果很有意思,现在分析如下:
第一次只执行构造函数是因为新建了A类的对象a,因此调用构造函数来构造对象,当main函数调用func函数的时候,将对象a的值传给了func函数,这个时候就要调用复制构造函数来做一个对象a的副本,当func函数执行完毕时,要将对象one返回,这个时候还要调用复制构造函数来做一个one对象的副本,然后调用析构函数释放func函数中的对象one,当回到main函数中的时候,由于返回的one对象没有使用,所以这个时候又要调用析构函数来释放这个返回的对象,当main函数执行完毕时,a对象的也该释放了,这个时候就要调用类的析构函数来释放a对象的空间。从上面的分析中我们看出这个过程中,有很多次调用,每次调用都要进行对象的复制,既浪费了内存,有降低了程序的执行效率。该怎么优化呢?这个时候我们可以使用传址的方式来进行,将代码修改如下:
#include <iostream>
using namespace std; class A
{
public:
A()
{
cout << "执行构造函数" << endl;
}
A(A&)
{
cout << "执行复制构造函数" << endl;
}
~A()
{
cout << "执行析构函数" << endl;
}
}; A func(A *one)
{
return (*one);
}
int main (void)
{
A a;
func(&a); return 0;
}
可以看到这里将传参的方式修改成了按址的方式,他的执行结果如下:
这里减少了一次复制构造函数和析构函数的调用,可以理解效率明显提高,但是要注意的是这里还有一对复制构造函数和析构函数的调用,这是为什么呢?仔细观察可以发现,func函数返回的是(*one),这是一个对象,而不是地址,所以他要调用复制构造函数来创建一个对象的副本,然后在析构。如果我们把func函数的返回类型修改为指针类型的时候就可以减少调用了:
#include <iostream>
using namespace std; class A
{
public:
A()
{
cout << "执行构造函数" << endl;
}
A(A&)
{
cout << "执行复制构造函数" << endl;
}
~A()
{
cout << "执行析构函数" << endl;
}
}; A *func(A *one)
{
return one;
}
int main (void)
{
A a;
func(&a); return 0;
}
这样,执行的结果就是:
这样就达到了对对象作为参数传递程序的最佳优化效果了!
C++按值和按址传递对象的思考和优化的更多相关文章
- C++ 值传递、址传递、引用传递
一.值传递 int func(int p) 值传递会在栈中开辟一块空间 p,使得p和实参的a 同值. 此时你在函数func里面对p进行任何操作都不会对原值a产生任何影响.因为a 和p本就就是两个变 ...
- [No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1
引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复 ...
- [No0000B9]C# 类型基础 值类型和引用类型 及其 对象复制 浅度复制vs深度复制 深入研究2
接上[No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1 对象复制 有的时候,创建一个对象可能会非常耗时,比如对象需要从远程数据库中获取数据来填充,又或者创建对象需要读取硬 ...
- 1. 元信息:Meta类 2. 基于对象查询的sql优化 3. 自定义:Group_Concat() 4. ajax前后台交互
一.元信息 ''' 1. 元信息 1. Model类可以通过元信息类设置索引和排序信息 2. 元信息是在Model类中定义一个Meta子类 class Meta: # 自定义表名 db_table = ...
- QDebug &operator<<出错(根据QString来找,是不得要领的,而是应该根据QString所在的对象来思考)
程序运行后,总是崩溃在这个地方:inline QDebug &operator<<(const QString & t) 我应该用什么办法找出是哪个QString出了问题呢 ...
- POJ 3046 Ant Counting(递推,和号优化)
计数类的问题,要求不重复,把每种物品单独考虑. 将和号递推可以把转移优化O(1). f[i = 第i种物品][j = 总数量为j] = 方案数 f[i][j] = sigma{f[i-1][j-k], ...
- 【javascript】详解变量,值,类型和宿主对象
前言 我眼中的<javascript高级程序设计> 和<你不知道的javascript>是这样的:如果<javascript高级程序设计>是本教科书的话, < ...
- 【转载自netfocus博客】聚合(根)、实体、值对象精炼思考总结
1.内容摘要 最近在看DDD领域驱动设计,看到实体(Entity),值对象 (Value Object),以及聚合根(Aggregate Root) 时.对他们的关系有些模糊,不清楚.于是去找了找资料 ...
- 【js jQuery】map集合 循环迭代取值---以及 map、json对象、list、array循环迭代的方法和区别
后台给前台传来一个map @ResponseBody @RequestMapping(value = "getSys") public Map<Long,String> ...
随机推荐
- 【css3+JavaScript】:一个优雅的对话框
实现效果: 演示地址:http://codepen.io/anon/pen/BNjYrR ======2015/5/11====== 优化滚动条(scroll):默认的滚动条太丑,忍不住优化下 ::- ...
- 【编程范式】汇编解释swap方法
先要熟悉一些汇编的基本知识: 1.SP是什么? SP是堆栈寄存器,在调用子程序时,都会用到,保存原来程序的环境使用,如各个寄存器的内容,最重要的是,调用返回时程序的运行指令地址,这是由调用时将返回地址 ...
- C++ Primer 学习笔记_77_模板与泛型编程 --实例化
模板与泛型编程 --实例化 引言: 模板是一个蓝图,它本身不是类或函数.编译器使用模板产生指定的类或函数的特定版本号.产生模板的特定类型实例的过程称为实例化. 模板在使用时将进行实例化,类模板在引用实 ...
- C-二维数组,多维数组
-----二维数组 ->在数组定义当中,行数和列数需要用常量定义 ->在定义的时候如果没有数值进行填充,则补零 ->第一个数是行,第二个数是列 ...
- bat处理文件
bat处理文件 作用:可以一次性执行多个命令的文件. 为什么要学bat处理文件? 快速运行一个软件一般都会把软件打包一个jar包,但是jar双击可以运行仅对图形化界面的软件起作用,对于控制台的程序是不 ...
- JavaScript深拷贝和浅拷贝
1. 基本类型 和 对象类型 他们最大的区别就是在于他们的传值方式. 基本类型是传值 对象类型就是传引用. 这里复制一份obj叫做obj2, 这里修改了obj2的b为100 同时也修改了obj1.b. ...
- C#中的一些复习。
摘自http://www.cnblogs.com/yuchengping/p/3151537.html 等日后自己来完善. 基本概念 1..NET是平台,C#是.NET上的一门语言. 2.C#的异常处 ...
- 老生常谈的Javascript作用域问题
在前端学习中,作用域这个问题一直被广泛提起,什么是作用域,什么又是作用域链?在Javascript中,怎么去理解这些概念都是学好这门语言的关键,所以在学习前端开发的过程中,我需要也很有必要去学习和总结 ...
- Windows下使用ODBC API访问数据库之关键
本文采用SQL2005 + VS2008环境,以ODBC API方式成功连接数据库. 1.SQL安装和环境配置 这部分网上随便搜一下都有很多资料,而且很容易就可以配置成功. 注意的关键点: SA账号配 ...
- 关于百度鹰眼中 xcode 7 编译报错问题
请把 这个地方改为 YES 否则demo 不能运行