c++ 堆栈中变量 想不明白,帮忙解释下 谢谢

j_now 2011-06-30 11:07:02
MyData 定义如下,超简单

const_ret_obj.h

#ifndef CONST_RET_OBJ
#define CONST_RET_OBJ
class MyData {
private:
static int SEQUENCE;
int id;
float source;
float revision;
void print(char *s="") const;
public:
MyData(float source=0);
MyData(const MyData& that);
~MyData();
void show() const;
void updateRevision();
};
#endif



const_ret_obj.cpp

#include <iostream>
#include <const_ret_obj.h>
using namespace std;

int MyData::SEQUENCE = 1;

MyData::MyData(float source)
: id(SEQUENCE++), source(source), revision(0.1) {
print("Constructor: ");
}

MyData::MyData(const MyData& that)
: id(SEQUENCE++), source(that.id + that.revision),
revision(0.1) {
print("CopyConstructor: ");
}

MyData::~MyData() {
print("Deconstructor: ");
}

void MyData::show() const {
print("show method: ");
}

void MyData::updateRevision() {
revision += 0.1;
}

void MyData::print(char *s) const {
cout << s << "MyData_Object id: " << id
<< ", source: " << source
<< ", revision: " << revision
<< ", addr: " << this << endl;
}






main:


#include "const_ret_obj.h"
#include <iostream>
using namespace std;

MyData f2() {
cout << "in f2()" << endl;

// same asm code as f1
return MyData();
}

MyData f1() {
cout << "in f1()" << endl;

// g++ optimize the two line with the same meaning of
// return MyData(2, 3);
MyData data;
return data; // correct in cpp
}

MyData g1() {
cout << "in g1() start" << endl;

// create a new object
MyData *data = new MyData();
data->show();

cout << "in g1() after new MyData" << endl;
return *data; // copy this object to main
// *data can not be recycled and reduce memory leak
}

int main(int argc, char *argv[]) {
MyData data0(); // a function named data0 is declared
int main_work_well(int argc, char *argv[]);


MyData data = f1();
cout << "in main() after f1 is called" << endl;
data.show();

data = f2();
cout << "in main() after f2 is called" << endl;
data.show();

data = g1();
cout << "in main() after g1 is called" << endl;
data.show();

if (1) return 0;

cout << endl << endl
<< "* * * * * * * * * *"
<< endl << endl;

return main_work_well(argc, argv);
}

int main_work_well(int argc, char *argv[]) {
MyData data0(); // a function named data0 is declared

MyData data1 = f1(); // id = 1
cout << "in main() after f1 is called" << endl;
data1.show();

MyData data2 = f2(); // id = 2
cout << "in main() after f2 is called" << endl;
data2.show();

MyData data3 = g1(); // id = 4
cout << "in main() after g1 is called" << endl;
data3.show();

return 0;
}



trace back: svn://www.oksvn.com/samples/tic1/ch8
使用 gcc 编译, 我知道main写的不对,但如果就这么写,如何解释输出的内容呢? 谢谢


in f1()
Constructor: MyData_Object id: 1, source: 0, revision: 0.1, addr: 0xbfb80a0c
in main() after f1 is called
show method: MyData_Object id: 1, source: 0, revision: 0.1, addr: 0xbfb80a0c
in f2()
Constructor: MyData_Object id: 2, source: 0, revision: 0.1, addr: 0xbfb80a18
Deconstructor: MyData_Object id: 2, source: 0, revision: 0.1, addr: 0xbfb80a18
in main() after f2 is called
show method: MyData_Object id: 2, source: 0, revision: 0.1, addr: 0xbfb80a0c
in g1() start
Constructor: MyData_Object id: 3, source: 0, revision: 0.1, addr: 0x80cf008
show method: MyData_Object id: 3, source: 0, revision: 0.1, addr: 0x80cf008
in g1() after new MyData
CopyConstructor: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfb80a24
Deconstructor: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfb80a24
in main() after g1 is called
show method: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfb80a0c
Deconstructor: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfb80a0c



...全文
320 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
五哥 2011-07-02
  • 打赏
  • 举报
回复
跟踪学习...
j_now 2011-07-02
  • 打赏
  • 举报
回复
额。。。。 自己系下
Louistao 2011-07-02
  • 打赏
  • 举报
回复
楼主可以在论坛里搜搜临时变量的帖子,以前看他们讨论过
qwer_boo 2011-07-02
  • 打赏
  • 举报
回复
j_now 2011-07-02
  • 打赏
  • 举报
回复
ok I will fix it myself.
cuipanda 2011-07-02
  • 打赏
  • 举报
回复
楼主直接问关键问题,代码太长了,看不下去,这样的发帖很难有解答。
j_now 2011-07-02
  • 打赏
  • 举报
回复
get it : http://club.topsage.com/thread-176965-1-1.html
j_now 2011-07-02
  • 打赏
  • 举报
回复
thx alot
pathuang68 2011-07-02
  • 打赏
  • 举报
回复
第70页附近的内容
pathuang68 2011-07-02
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 j_now 的回复:]

感谢大家的建议,我把问题缩短,我的编译器版本是gcc version 4.1.2 20070925

C/C++ code

#include "const_ret_obj.h"

MyData f(void) {
return MyData();
} ……
[/Quote]
第一个问题,主要是牵涉了编译器优化。
第二个问题,也牵涉到了编译器优化。如果你写成这样:

MyData data1 = f();
MyData data2(data1); // 这样就会调用Copy Constructor了。


建议楼主看看Inside C++ Object Model中文版
j_now 2011-07-02
  • 打赏
  • 举报
回复
感谢大家的建议,我把问题缩短,我的编译器版本是gcc version 4.1.2 20070925


#include "const_ret_obj.h"

MyData f(void) {
return MyData();
}

int main(void) {
MyData data = f();
data = f();

return 0;
}

问题:
1. 在MyData data = f();中,直接把main函数栈禎(stack frame)中的data地址传递给了f(),在 data=f()调用中,为什么不止解把data传递给main,而是在main函数栈禎中又创建了一个临时变量?

2. 在 data = f(); 调用的过程中,为什么把临时对象拷贝到data中时没有调用拷贝构造函数?

谢谢



j_now 2011-07-02
  • 打赏
  • 举报
回复
上面的格式太乱了 重新粘一下


MyData data = f1(); in main
eax 0xbff4ddc8 -1074471480 # 0xbff4ddc8 is a stack address in main function, it is the addr of data
ecx 0xbff4de00 -1074471424
edx 0x1 1
ebx 0x4e3ff4 5128180
esp 0xbff4dda0 0xbff4dda0
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048af8 0x8048af8 <main+24>
eflags 0x200286 [ PF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


MyData data = f2(); in main
eax 0xbff4ddd0 -1074471472 # 0xbff4ddd0 is a stack address in main function, a temporary variable addr
ecx 0x0 0
edx 0x4e50b0 5132464
ebx 0x4e3ff4 5128180
esp 0xbff4dda0 0xbff4dda0
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048b35 0x8048b35 <main+85>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


after f2() is returned.
eax 0xbff4ddd0 -1074471472
ecx 0x0 0
edx 0x4e50b0 5132464
ebx 0x4e3ff4 5128180
esp 0xbff4dda4 0xbff4dda4
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048b3a 0x8048b3a <main+90>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


so ebp is 0xbff4dde8,x/30 0xbfbd0a18
0xbff4ddc8: [0x00000001] 0xbf800000 <0x00000002> 0xbf800000 # here is 0xffffffe8(%ebp) wrapped with <>
0xbff4ddd8: 0xbff4dde8 0x004e3ff4 0xbff4de00 0x004e3ff4 # previous line is 0xffffffe0(%ebp) wrapped with []
0xbff4dde8: 0xbff4de58 0x003a5390 0x0038bca0 0x08048e80
0xbff4ddf8: 0xbff4de58 0x003a5390 0x00000001 0xbff4de84
0xbff4de08: 0xbff4de8c 0x0038c810 0x00000000 0x00000001

the asm code listed below
0x08048b35 <main+85>: call 0x8048890 <_Z2f2v>
0x08048b3a <main+90>: sub $0x4,%esp
0x08048b3d <main+93>: mov 0xffffffe8(%ebp),%eax # BFF4DDE8+FFFFFFE8= 1,BFF4DDD0,i.e. temporary variable
0x08048b40 <main+96>: mov %eax,0xffffffe0(%ebp) # BFF4DDE8+FFFFFFE0= 1,BFF4DDC8,i.e. data variable
0x08048b43 <main+99>: mov 0xffffffec(%ebp),%eax
0x08048b46 <main+102>: mov %eax,0xffffffe4(%ebp)
0x08048b49 <main+105>: lea 0xffffffe8(%ebp),%eax
0x08048b4c <main+108>: mov %eax,(%esp)
0x08048b4f <main+111>: call 0x8048d3c <~MyData>


因此 c++ 没有调用拷贝构造函数,虽然已经声明了一个拷贝构造函数,但是还是使用了内存拷贝
j_now 2011-07-02
  • 打赏
  • 举报
回复
MyData data = f1(); in main
eax 0xbff4ddc8 -1074471480 # 0xbff4ddc8 is a stack address in main function, it is the addr of data
ecx 0xbff4de00 -1074471424
edx 0x1 1
ebx 0x4e3ff4 5128180
esp 0xbff4dda0 0xbff4dda0
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048af8 0x8048af8 <main+24>
eflags 0x200286 [ PF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


MyData data = f2(); in main
eax 0xbff4ddd0 -1074471472 # 0xbff4ddd0 is a stack address in main function, a temporary variable addr
ecx 0x0 0
edx 0x4e50b0 5132464
ebx 0x4e3ff4 5128180
esp 0xbff4dda0 0xbff4dda0
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048b35 0x8048b35 <main+85>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


after f2() is returned.
eax 0xbff4ddd0 -1074471472
ecx 0x0 0
edx 0x4e50b0 5132464
ebx 0x4e3ff4 5128180
esp 0xbff4dda4 0xbff4dda4
ebp 0xbff4dde8 0xbff4dde8
esi 0x38bca0 3718304
edi 0x0 0
eip 0x8048b3a 0x8048b3a <main+90>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51


so ebp is 0xbff4dde8,x/30 0xbfbd0a18
0xbff4ddc8: [0x00000001] 0xbf800000 <0x00000002> 0xbf800000 # here is 0xffffffe8(%ebp) wrapped with <>
0xbff4ddd8: 0xbff4dde8 0x004e3ff4 0xbff4de00 0x004e3ff4 # previous line is 0xffffffe0(%ebp) wrapped with []
0xbff4dde8: 0xbff4de58 0x003a5390 0x0038bca0 0x08048e80
0xbff4ddf8: 0xbff4de58 0x003a5390 0x00000001 0xbff4de84
0xbff4de08: 0xbff4de8c 0x0038c810 0x00000000 0x00000001

the asm code listed below
0x08048b35 <main+85>: call 0x8048890 <_Z2f2v>
0x08048b3a <main+90>: sub $0x4,%esp
0x08048b3d <main+93>: mov 0xffffffe8(%ebp),%eax # BFF4DDE8+FFFFFFE8= 1,BFF4DDD0,i.e. temporary variable
0x08048b40 <main+96>: mov %eax,0xffffffe0(%ebp) # BFF4DDE8+FFFFFFE0= 1,BFF4DDC8,i.e. data variable
0x08048b43 <main+99>: mov 0xffffffec(%ebp),%eax
0x08048b46 <main+102>: mov %eax,0xffffffe4(%ebp)
0x08048b49 <main+105>: lea 0xffffffe8(%ebp),%eax
0x08048b4c <main+108>: mov %eax,(%esp)
0x08048b4f <main+111>: call 0x8048d3c <~MyData>


因此 c++ 没有调用拷贝构造函数,虽然已经声明了一个拷贝构造函数,但是还是使用了内存拷贝
野男孩 2011-07-01
  • 打赏
  • 举报
回复
in f1()
Constructor: MyData_Object id: 1, source: 0, revision: 0.1, addr: 0012FF38
CopyConstructor: MyData_Object id: 2, source: 1.1, revision: 0.1, addr: 0012FF60

Deconstructor: MyData_Object id: 1, source: 0, revision: 0.1, addr: 0012FF38
in main() after f1 is called
show method: MyData_Object id: 2, source: 1.1, revision: 0.1, addr: 0012FF60
in f2()
Constructor: MyData_Object id: 3, source: 0, revision: 0.1, addr: 0012FF6C
Deconstructor: MyData_Object id: 3, source: 0, revision: 0.1, addr: 0012FF6C
in main() after f2 is called
show method: MyData_Object id: 3, source: 0, revision: 0.1, addr: 0012FF60
in g1() start
Constructor: MyData_Object id: 4, source: 0, revision: 0.1, addr: 00361C58
show method: MyData_Object id: 4, source: 0, revision: 0.1, addr: 00361C58
in g1() after new MyData
CopyConstructor: MyData_Object id: 5, source: 4.1, revision: 0.1, addr: 0012FF6C

Deconstructor: MyData_Object id: 5, source: 4.1, revision: 0.1, addr: 0012FF6C
in main() after g1 is called
show method: MyData_Object id: 5, source: 4.1, revision: 0.1, addr: 0012FF60
Deconstructor: MyData_Object id: 5, source: 4.1, revision: 0.1, addr: 0012FF60
Press any key to continue

你这输出和我这里差别好大。。。。。编译器优化得不一样吧
菜鸟一个 2011-07-01
  • 打赏
  • 举报
回复
帮你顶下 也太长了。。
luciferisnotsatan 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 pengzhixi 的回复:]

关于临时对象,返回值优化去看看深入C++对象模型。
[/Quote]
++

MyData data1 = f1();
编译器直接把这里会产生的零时对象优化掉了。
至善者善之敌 2011-07-01
  • 打赏
  • 举报
回复
啥编译器?代码太长了。。帮顶
pengzhixi 2011-07-01
  • 打赏
  • 举报
回复
关于临时对象,返回值优化去看看深入C++对象模型。
j_now 2011-07-01
  • 打赏
  • 举报
回复
没有别的什么解释么?
j_now 2011-06-30
  • 打赏
  • 举报
回复
尤其是: ./const_ret_obj_main | grep Decons

Deconstructor: MyData_Object id: 2, source: 0, revision: 0.1, addr: 0xbfa84128
Deconstructor: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfa84134
Deconstructor: MyData_Object id: 4, source: 3.1, revision: 0.1, addr: 0xbfa8411c

很奇怪,id=4的~MyData 被 call了两次, id=1 的一次也没有被call到。。。 无语了

期盼解答,thx alot
加载更多回复(1)

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧