StupidBeauty
Read times:3104Posted at:Tue Oct 3 03:23:19 2017 - no title specified

《C++面向对象软件设计及构建》文章翻译:2.9动态对象,2.9 Dynamic Objects

动态对象,它们的生命周期,与创建它们的那个作用域无关。因此,在某个函数中创建的对象,可以在该函数返回之后仍然存在;或者,可以在某个if-then 结构中创建对象,那些对象在该个if-then 结构执行完毕之后仍然存在。动态对象,为程序猿提供了更大的灵活性,便于管理对象。同时,程序猿也承担着更大的责任,需要确保动态对象处于正确的管理之下。对于动态对象,有两种可能的问题会出现:将对象销毁得过早;以及,根本就不将对象进行销毁。

动态对象,是通过"new"操作符来创建的,它返回一个指针,指向刚刚构造的对象。动态对象,是通过"delete"操作符来销毁的。要使用一个指针变量来容纳由new 操作符返回的对象的指针。delete操作符,需要一个指针变量作为参数,它会销毁由那个变量所指向的对象。以下示例,展示了,动态对象该如何创建及销毁。

Frame *window, *view;                // 指针变量 的声明

window = new Frame("First", 10, 20, 50, 50); // 创建 一个新的 Frame对象

view   = new Frame("Second",70, 20, 50, 50); // 创建 一个新的Frame对象

Frame *edit = new Frame ("Editor", 50, 75, 100, 100); // 将指定变量的声明

// 和对象的构造配套使用

Frame *default = new Frame;          // 使用默认 的构造函数参数值

delete window;                       // 销毁window 这个 Frame

delete view;                         // 销毁view 这个 Frame

delete edit;                         // 销毁edit 这个 Frame

delete default;                      // 销毁default 这个 Frame

在这个示例中,windowview,是声明出来的两个变量,它们将会指向Frame 对象。有一点狠重要,那就是,这个声明语句中, 并不会 创建两个框框对象(frames);它只是创建两个变量,它们将会指向Frame 对象,而那些对象也只是会在日后的某个时刻被创建出来。然后,就创建了那两个Frame 对象,而"window"和"view"变量就被操作以指向那两个对象了。指针变量的声明,以及它所指向的对象的构造,可以配套起来写到单条语句中去,对于edit 和default 即是这种用法。最后,这四个Frame 对象都被销毁了。

注意看,创建动态对象的语法是什么样的。类的名字,直接放在关键字"new"之后。如果需要提供任何构造函数参数的话,那么,就放置在类名字之后的括号中。如果不需要提供构造函数参数,那么,可以将括号省略掉,就像示例中的default 对象一样。

在对动态对象进行操作时,应当使用 -> 操作符。 这里的“箭头”操作符,是两个紧挨在一起的字符,分别是一个减号和一个大于符号。 以下示例,展示了,如何对一个动态对象进行操作:

Frame* display = new Frame ("A Display", 10, 20, 100, 200);

display->MoveTo(50, 50);

display->Resize(200, 200);

在这个示例中,使用了箭头操作符来调用display 对象的方法,将对象移动位置,及改变大小。

如果未能正确地使用动态对象,那么,可能导致两种严重的错误。这些错误,因为两种原因而变得狠严重。首先,这种错误,可能导致程序终止运行,或者做出预期之外的行为。其次,在实际的程序中,这种错误,是最难找到其原因的错误之一。

对于动态对象,在它向上,可能出现的第一种错误,就是,过早地销毁某个动态对象。以下示例中,展示的情况是,某个对象,被两个不同的Frame 变量所指向,分别是display 和view。这个共享的对象,被"delete display;"语句所销毁。之后,如果再试图使用view 变量来对已经销毁的对象做操作,就会出错。

Frame *display = new Frame ("Shared", 10, 20, 100, 100);

Frame *view;

view = display;              // 两个变量指向 同一个Frame 对象

display->MoveTo(50, 50);     // 正确 - 将共享的Frame 对象移动到新位置

view->Resize(200, 200);      // 正确 - 将共享的Frame 对象改变大小

delete display;              // 销毁 这个 共享 对象

view->MoveTo(20, 20);        // 错误 - 这个对象已经被销毁了!

当妳使用已经被销毁的对象时,最好的结果就是,程序终止运行。在这种情况下,进行调试时的切入点,通常都能够放置到实际出问题的位置处,或者就在实际出问题的位置附近。然而,程序仍然有可能继续运行,这样就会糟糕得多。运行时系统,可能并未检测到该个对象已经被销毁了,于是就会继续对该个对象之前所占用的内存进行变动。这种事,其后果,是无法预料的。通常遇到的后果是,程序中的其它部分发现,某个对象,被莫名其妙地破坏掉了。要想在一个巨大的程序中找到这种问题的原因,是超级困难的。

在使用动态对象的过程中,可能出现的第二种错误,就是,并不去销毁一个本身已经无法访问到的对象。这种类型的错误,被称为“内存泄漏”,因为,可用内存的整个池子,相当于慢慢漏掉了。在一个长期 运行的程序(空中交通管理、电子转账,等等)中,可能会最终泄漏掉足够多的内存,以致于程序终止运行。严重的内存泄漏,可能导致几百兆的内存被泄漏掉。

以下示例,展示了,一种内存泄漏的场景。

Frame *display;

for (int i=0; i<100; i++) {

display = new Frame ("Memory Leak", 50, 50, 100, 100);

// 使用 display ,但是没有销毁它

}

在这个示例中,创建了100Frame对象,但是,没有一个对象被销毁掉。而同时,只有最后一个Frame 对象还是可访问的,因为,指向前面那些对象的指针,已经被覆盖掉了。然而,用于容纳这些对象的内存,仍然处于占用状态。对于运行时系统来说,这个程序仍然在使用这些内存,然而这个程序本身已经没有任何手段来访问到这些对象了。于是,这些内存,处于占用且不可访问状态 - 它们泄漏了。

以上两个示例中,出现的错误,狠容易找到,因为,每个示例中只有一点点代码。但是,想象一下,在某个程序中,有数以十计的类,数以百计的方法,数以千计的对象,并且系统中不同的部分共享着大量的对象。在这种情况下 - 这也是真正重要的使用场景 - 就极难找到这种类型的错误的原因了。

任务

  1. 1. 简单对话框 :编写 一个程序,显示一个Frame,其中显示着文字 "Click Here for Help"(“点击这里以获得帮助”) 当用户在这个Frame 中点击鼠标左键时,动态创建一个新的Frame,其中显示两行文字: "Yes Master. You Rang?" (“妳好,老板。找我有事吗?”) "Click to Dismiss." (“点击即关闭。”) 当用户在动态创建的Frame 中点击鼠标左键时,该Frame 应当被销毁。分析 妳的程序,判断一下,其中是否有潜在的内存泄漏可能性。 不需要修复它; 只需要确认是否存在问题。

  2. 2.重写之前的角落旅行程序,只使用一个动态Frame 对象。

  3. 3.重写之前的角落旅行程序,使得,到达每个角落时,创建一个新的动态Frame 对象,并且销毁之前角落处创建的对象。

  4. 4.重写之前的边界漫游程序,只使用一个动态Frame 对象。

  5. 5.重写之前的边界漫游程序,使得,每走一步,就创建一个新的动态Frame 对象。

  6. 6.编写一个程序,故意访问某个已经被销毁的Frame 对象。结果如何?

  7. 7.编写一个程序,它会泄漏Frame 对象。这个程序在终止之前,运行了多久?它是如何终止运行的?

未知美人

https://plus.google.com/communities/101307299870001617052/stream/04445a0c-5586-44b8-a974-be36b82ca870

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands