64,648
社区成员
发帖
与我相关
我的任务
分享
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;
}
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
MyData data1 = f();
MyData data2(data1); // 这样就会调用Copy Constructor了。
#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中时没有调用拷贝构造函数?
谢谢
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++ 没有调用拷贝构造函数,虽然已经声明了一个拷贝构造函数,但是还是使用了内存拷贝