作者s5031588 (好马儿)
看板C_and_CPP
标题[问题] class destructor
时间Sun Oct 8 20:45:23 2017
▉▂
开发平台(Platform): (Ex: Win10, Linux, ...)
MacOSX
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
g++5.4
问题(Question):
大家好,最近在修资料结构这门课,过去虽然有修过计算机程式
,但是两学分的课所以感觉学得不是很扎实,对於class的部分只有粗略带过..
所以来这边请教大家:
对於一个data member中含有pointer的class,初始时会用new配置记忆体,
而自行建立的destructor会用delete释放配置给该指标的记忆体,请问这样的状况下
该怎麽在member function中回传一个local的class变数呢?
因为函数功能的需要,必须在函数中宣告一个class变数a来承接运算的结果,并return
该变数给calling function,由calling function中的class变数b承接,但是这样的情
况下,由於member function terminates, destructor将a里面的pointer给delete掉,
造成calling function中b里面的指标指向一个直随时有可能被修改的地方...
有自己试着去overload operator=及建立copy constructor来看看是否可以让calling
function 中b里面的pointer指向一个新的地方,在复制a的值过去,但好像a会先被
destructed(?!)..
上网查了很多destructor, return object的关键字,都找不到想要的答案..
在这里麻烦大家解答了..
在下面附上class 的程式码,大致上是我在建立一个stack的class 有一个destructor:
~Stack(){delete [] stack
初始的constructor有用new给该指标动态配置记忆体
问题卡在是我要写一个member function splitStack(),作用是要将某个stack从中间
某个点分开拆成两个stack,所以这个function 必须return stack型态的variable,
但是splitStack()中宣告的first再回传值给main後,就被解构了..
程式码(Code):(请善用置底文网页, 记得排版)
http://codepad.org/IjGU1cDW
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.47.182.50
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1507466726.A.1A7.html
1F:推 jerryh001: 是要定义copy constructor没错 看看有没有哪里写错 10/08 21:07
2F:→ jerryh001: 发现个奇怪的地方 destructor不应该手动呼叫 10/08 21:08
3F:→ s5031588: 请问j大 copy constructor该怎麽写呢?因为我造我的逻 10/08 22:07
4F:→ s5031588: 辑写还是没办法欸..附上我copy constructor的程式码: 10/08 22:08
7F:→ s5031588: 我用一步步执行发现,虽然copy function不会让两个 10/08 22:21
8F:→ s5031588: POINTER 直接相等,但是splitStack一结束,居然会 10/08 22:22
9F:→ s5031588: 两个指标都destruct...= =,有人可以解释原理吗QQ 10/08 22:22
10F:→ jerryh001: operator=也要留吧 10/08 22:40
11F:→ jerryh001: copy ctor 的参数也许也要<T>吗? 有点忘了 10/08 22:42
12F:→ stucode: 怎麽写完 copy ctor 後 operator = 就不见了XD? 10/08 23:20
13F:→ stucode: 1. copy constructor 里面不用 delete,因为是初始化, 10/08 23:20
14F:→ stucode: 还没有前值,直接 new 然後 copy 就好。 10/08 23:20
15F:→ stucode: 2. copy assignment 需要检查并释放(或重新利用)现有 10/08 23:20
16F:→ stucode: 资源,同时要避免 self-assignment 造成错误的 10/08 23:21
17F:→ stucode: delete。 10/08 23:21
18F:→ stucode: 3. copy assignment 请传回 reference,不要传值。 10/08 23:21
19F:→ stucode: 4. splitStack() return first 就好,不用再包一层。 10/08 23:21
20F:→ stucode: 其实你的指标几乎都是在 3. 或 4. 多余的临时物件中被 10/08 23:21
21F:→ stucode: delete 掉的。不过如果有做好 deep copy,顶多就是多跑 10/08 23:22
22F:→ stucode: 几次 copy 效能较差而已,也不至於会使用到被 delete 10/08 23:22
23F:→ stucode: 掉的指标,造成严重错误。 10/08 23:22
喔喔喔了解了,真的是犯傻才会把operator=又删掉XDD,现在程式可以work了,
非常感谢j大跟s大的解说!
不过想另外请教s大,关於第三点,为什麽会说传回reference呢?是因爲传回值
有什麽缺点吗?谢谢。
※ 编辑: s5031588 (114.47.182.50), 10/09/2017 00:44:19
24F:推 lc85301: 传回reference 是要允许使用 move 来减少一次 copy 吧 10/09 01:04
25F:→ stucode: 传回值的话,比较容易产生不必要的临时物件。除此之外, 10/09 05:57
26F:→ stucode: 还可能导致非使用者预期的行为。其实 C++ 并没有硬性规 10/09 05:57
27F:→ stucode: 定 copy assignment 要传回 reference。这比较像是一种 10/09 05:57
28F:→ stucode: 惯例,让自定义类别的行为尽可能相似於 C++ 原生型别 10/09 05:58
29F:→ stucode: (如 int)的行为。减少类别使用时产生意料之外的效果。 10/09 05:58
30F:→ stucode: 另外一个理由是,CopyAssignment requirements 要求回传 10/09 05:58
31F:→ stucode: 型态必须是 T&,没有满足这个条件可能无法正常使用某些 10/09 05:58
32F:→ stucode: 标准容器的方法。事实上,如果没有为类别宣告这个函数, 10/09 05:58
33F:→ stucode: 编译器自动帮你生成的版本也是传回 reference。当然,如 10/09 05:58
34F:→ stucode: 果你有更好的理由传回新物件或者是其他型别,那就不用客 10/09 05:58
35F:→ stucode: 气的传吧!只要确保使用者了解并正确使用你的类别即可。 10/09 05:59
谢谢s大与l大的回覆,原来回传值会产生一个临时物件,一直以为回传的值会直接
回到main,由main里面的物件去接收...看来我原本误会很深
再次感谢三位的回覆。
※ 编辑: s5031588 (49.215.209.133), 10/09/2017 09:16:04
36F:推 james732: 顺便学一下什麽是rvalue reference与move吧XD 10/09 10:02
回james:好的我会研究看看,谢谢建议。
照着大家说得下去改了程式码:
http://codepad.org/RYcz2e7B
main:
http://codepad.org/cM17bFfK
为什麽我原本用b=a.splitStack(1)的时候,当等式结束的时候splitStack()里面的first
会被destructor给删除,然而改成上面main里面的方式用Stack b(a.splitStack(1))时,
却没有呼叫destructor来解构first的迹象...?
另外,为什麽用copy assignment的时候,似乎是等到等号结束时,程式才会呼叫
destructor来解构first,而不是splitStack一结束就呼叫呢?
我好乱啊..QQ
※ 编辑: s5031588 (49.215.209.133), 10/09/2017 10:52:07
37F:→ Caesar08: 如果你想要预先allocate一些memory来用,你需要知道 10/09 13:50
38F:→ Caesar08: placement new才行。今天destructor没问题是因为T是int 10/09 13:50
39F:→ Caesar08: 建议先看gcc或msvc的vector怎麽实作vector,再实作stack 10/09 13:51
40F:→ stucode: 实测了一下,解构都正常喔。如果你有开最佳化(或者是 10/09 20:09
41F:→ stucode: IDE 的 Release mode),那 first 可能被 RVO 掉,实际 10/09 20:09
42F:→ stucode: 解构会在 b 生命周期结束时(离开 main() 时)发生。 10/09 20:09
43F:→ stucode: 另外,复制建构函数里的 new 括号错了。 10/09 20:09
谢谢c大的回答,我会再参考看看。
回s大:我不知道我有没有开最佳化欸,我不管在xcode里面跑(似乎是debug mode
我也不知道怎麽看,整个IDE我只会有按过run跟新增专案而已..惨)还是用终端机跑
g++-5 main.cpp的指令出来的结果就是destructor只被呼叫了两次(最後离开main的时
候),後来一步步看,似乎跑的时候系统一开始就直接把first.stack与b.stack指向
同一个地方了,所以最後destructor只有呼叫两次,一次是delete a.stack
另一次是delete b.stack(first.stack),似乎这就是s大你说的first被RVO..
再次感谢s大,还让你帮我跑一次~
※ 编辑: s5031588 (36.236.99.33), 10/10/2017 12:16:25