首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
schema
web3
integer
stream
php5
require
tags
solr
split
regex
heap
node.js
email
command
object
spring
js
grid
request
flutter
char
hashset
config
php7
rsa
shell
join
hook
httprequest
blob
go
keyword
golang
hashtable
uml
actionscrip
settings
select
ip
chat
callback
python2
bit
loops
byte
window
cSharp
erlang
list
heatmap
text
input
jar
format
triggers
header
typescript
default
controller
io
plugins
cookie
python3
vba
ascii
runtime
iostream
fetch
python
timestamp
random
数组
range
metadata
hashcode
httpclient
import
bitmap
emoji
当前位置:
开发笔记
>
编程语言
> 正文
string对象被覆盖了,奇怪的问题!
作者:tuiqiu | 来源:互联网 | 2023-09-03 12:09
#include<stdio.h>#include<stdlib.h>#include<iostream>#include<string&
#include
#include
#include
#include
using namespace std;
string f() { return "hello";}
int main() {
const char * str = f().c_str();
cout << str<< endl;
string b = string("ppppp");
printf("str=[%p], b=[%p]\n", str, b.c_str());
cout << str << endl;
b = "ddddd";
cout << str << endl;
return 1;
}
结果是:
hello
str=[0x], b=[0x]
ppppp
ddddd
为什么不是:
hello
str=[0x], b=[0x]
hello
hello
?
百思不得其解
6 个解决方案
#1
我百思不得其解的是我都得不到你说的任何一种结果。
#2
什么骡子玩意?
#3
代码风格极其恶劣!
#4
函数 f 返回的临时对象已经被释放了。
#5
引用 1 楼 healer_kx 的回复:
我百思不得其解的是我都得不到你说的任何一种结果。
#6
条款22: 尽量用“传引用”而不用“传值”
c语言中,什么都是通过传值来实现的,c++继承了这一传统并将它作为默认方式。除非明确指定,函数的形参总是通过“实参的拷贝”来初始化的,函数的调用者得到的也是函数返回值的拷贝。
正如我在本书的导言中所指出的,“通过值来传递一个对象”的具体含义是由这个对象的类的拷贝构造函数定义的。这使得传值成为一种非常昂贵的操作。例如,看下面这个(只是假想的)类的结构:
class person {
public:
person(); // 为简化,省略参数
//
~person();
...
private:
string name, address;
};
class student: public person {
public:
student(); // 为简化,省略参数
//
~student();
...
private:
string schoolname, schooladdress;
};
现在定义一个简单的函数returnstudent,它取一个student参数(通过值)然后立即返回它(也通过值)。定义完后,调用这个函数:
student returnstudent(student s) { return s; }
student plato; // plato(柏拉图)在
// socrates(苏格拉底)门下学习
returnstudent(plato); // 调用returnstudent
这个看起来无关痛痒的函数调用过程,其内部究竟发生了些什么呢?
简单地说就是:首先,调用了student的拷贝构造函数用以将s初始化为plato;然后再次调用student的拷贝构造函数用以将函数返回值对象初始化为s;接着,s的析构函数被调用;最后,returnstudent返回值对象的析构函数被调用。所以,这个什么也没做的函数的成本是两个student的拷贝构造函数加上两个student析构函数。
但没完,还有!student对象中有两个string对象,所以每次构造一个student对象时必须也要构造两个string对象。student对象还是从person对象继承而来的,所以每次构造一个student对象时也必须构造一个person对象。一个person对象内部有另外两个string对象,所以每个person的构造也必然伴随另两个string的构造。所以,通过值来传递一个student对象最终导致调用了一个student拷贝构造函数,一个person拷贝构造函数,四个string拷贝构造函数。当student对象被摧毁时,每个构造函数对应一个析构函数的调用。所以,通过值来传递一个student对象的最终开销是六个构造函数和六个析构函数。因为returnstudent函数使用了两次传值(一次对参数,一次对返回值),这个函数总共调用了十二个构造函数和十二个析构函数!
在c++编译器的设计者眼里,这是最糟糕的情况。编译器可以用来消除一些对拷贝构造函数的调用(c++标准——见条款50——描述了具体在哪些条件下编译器可以执行这类的优化工作,条款m20给出了例子)。一些编译器也这样做了。但在不是所有编译器都普遍这么做的情况下,一定要对通过值来传递对象所造成的开销有所警惕。
为避免这种潜在的昂贵的开销,就不要通过值来传递对象,而要通过引用:
const student& returnstudent(const student& s)
{ return s; }
这会非常高效:没有构造函数或析构函数被调用,因为没有新的对象被创建。
通过引用来传递参数还有另外一个优点:它避免了所谓的“切割问题(slicing problem)”。当一个派生类的对象作为基类对象被传递时,它(派生类对象)的作为派生类所具有的行为特性会被“切割”掉,从而变成了一个简单的基类对象。这往往不是你所想要的。例如,假设设计这么一套实现图形窗口系统的类:
class window {
public:
string name() const; // 返回窗口名
virtual void display() const; // 绘制窗口内容
};
class windowwithscrollbars: public window {
public:
virtual void display() const;
};
每个window对象都有一个名字,可以通过name函数得到;每个窗口都可以被显示,着可以通过调用display函数实现。display声明为virtual意味着一个简单的window基类对象被显示的方式往往和价格昂贵的windowwithscrollbars对象被显示的方式不同(见条款36,37,m33)。
现在假设写一个函数来打印窗口的名字然后显示这个窗口。下面是一个用错误的方法写出来的函数:
// 一个受“切割问题”困扰的函数
void printnameanddisplay(window w)
{
cout << w.name();
w.display();
}
想象当用一个windowwithscrollbars对象来调用这个函数时将发生什么:
windowwithscrollbars wwsb;
printnameanddisplay(wwsb);
参数w将会作为一个windows对象而被创建(它是通过值来传递的,记得吗?),所有wwsb所具有的作为windowwithscrollbars对象的行为特性都被“切割”掉了。printnameanddisplay内部,w的行为就象是一个类window的对象(因为它本身就是一个window的对象),而不管当初传到函数的对象类型是什么。尤其是,printnameanddisplay内部对display的调用总是window::display,而不是windowwithscrollbars::display。
解决切割问题的方法是通过引用来传递w:
// 一个不受“切割问题”困扰的函数
void printnameanddisplay(const window& w)
{
cout << w.name();
w.display();
}
现在w的行为就和传到函数的真实类型一致了。为了强调w虽然通过引用传递但在函数内部不能修改,就要采纳条款21的建议将它声明为const。
传递引用是个很好的做法,但它会导致自身的复杂性,最大的一个问题就是别名问题,这在条款17进行了讨论。另外,更重要的是,有时不能用引用来传递对象,参见条款23。最后要说的是,引用几乎都是通过指针来实现的,所以通过引用传递对象实际上是传递指针。因此,如果是一个很小的对象——例如int——传值实际上会比传引用更高效。
string
include
io
ios
int
main
const
char
c语言
写下你的评论吧 !
吐个槽吧,看都看了
会员登录
|
用户注册
推荐阅读
ocr
MFC动态创建窗口的实现方法及注意事项
本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ...
[详细]
蜡笔小新 2023-12-11 15:09:27
char
C++字符字符串处理及字符集编码方案
本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ...
[详细]
蜡笔小新 2023-12-13 04:59:58
js
HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ...
[详细]
蜡笔小新 2023-12-14 15:08:18
js
Android源码深入理解JNI技术的概述和应用
本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ...
[详细]
蜡笔小新 2023-12-13 10:00:57
js
C#多线程解决界面卡死问题的完美解决方案
当界面需要在程序运行中不断更新数据时,使用多线程可以解决界面卡死的问题。一个主线程创建界面,使用一个子线程执行程序并更新主界面,可以避免卡死现象。本文分享了一个例子,供大家参考。 ...
[详细]
蜡笔小新 2023-12-10 10:37:32
js
lua语言闭包、模式匹配、日期、编译、模块的特性及应用
本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ...
[详细]
蜡笔小新 2023-12-14 18:18:21
object
C#学习教程:在Console中工作但在Windows窗体中不工作的异步代码分享
本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ...
[详细]
蜡笔小新 2023-12-14 15:56:00
object
Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ...
[详细]
蜡笔小新 2023-12-12 20:56:55
char
lintcode(12)——最小子串覆盖的解题思路和代码实现
本文介绍了lintcode(12)题目的要求和解题思路,以及给出了相应的代码实现。题目要求在给定的字符串source中找到包括所有目标字符串字母的最短子串,并且时间复杂度为O(n)。解题思路是使用滑动窗口的方法,通过维护一个unordered_map来记录目标字符串中每个字符的出现次数,并使用双指针来寻找最小子串。代码实现部分给出了具体的实现代码。 ...
[详细]
蜡笔小新 2023-12-11 13:29:51
char
如何在HTML中获取鼠标的当前位置
本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ...
[详细]
蜡笔小新 2023-12-11 13:04:00
grid
pack布局管理器的使用方法及注意事项
本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ...
[详细]
蜡笔小新 2023-12-10 16:03:24
grid
Android View(一)-View坐标以及方法说明
本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ...
[详细]
蜡笔小新 2023-12-10 13:13:29
grid
解决PyQt界面在高分辨率下字体显示不完全的方法
本文介绍了一种解决PyQt界面在高分辨率下字体显示不完全的方法。通过设置High_DPI属性或应用自适应字体,可以解决在更高分辨率电脑上字体被控件遮挡的问题。同时,还提供了判断Qt版本和设置字体大小的代码示例。 ...
[详细]
蜡笔小新 2023-12-10 03:21:11
require
解决mysql 5.1启动问题的方法
本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ...
[详细]
蜡笔小新 2023-12-09 21:14:55
js
JS兼容总结及解决方法
本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ...
[详细]
蜡笔小新 2023-12-09 17:31:06
tuiqiu
这个家伙很懒,什么也没留下!
Tags | 热门标签
schema
web3
integer
stream
php5
require
tags
solr
split
regex
heap
node.js
email
command
object
spring
js
grid
request
flutter
char
hashset
config
php7
rsa
shell
join
hook
httprequest
blob
RankList | 热门文章
1
oracle 数据文件,控制文件和参数文件全部丢失恢复
2
Decoration5:引入Actuator进行站点监控
3
JVM学习笔记|垃圾回收相关算法
4
【风马一族_软件】微软卸载工具_msicuu2.exe
5
JAVA中流水账的实现_流水账式java基础Summary
6
zookeeper和hadoop集群(伪分布式)
7
C#学习教程:有没有理由锁定除new object()之外的东西?分享
8
学习java 需要先学c 吗_学习Java需要先学C语言吗
9
vue3.x全局toast、message、loading组件
10
Oracle查看用户占用的表空间大小
11
RecycleView 中的item移动到当前视图的顶部
12
2022网易雷火游戏研发笔试ak(4月23日)
13
64位驱动 hp630打印机_hp1020打印机64位驱动下载
14
大学生竞赛管理系统项目
15
http://www.bootstrapswitch.org/examples.html Not Loading
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有