我正在处理一个名为Stopwatch
的课程(所以请忽略下面的大部分不完整性)。它的界面应该是秒表在现实生活中的一个很好的抽象。现在我正在尝试编写析构函数,它将释放代表所有圈数的链表的内存。
class Stopwatch
{
typedef enum {UNSTARTED, RUNNING, PAUSED, FINISHED} state;
typedef struct
{
unsigned hours;
unsigned minutes;
unsigned seconds;
} time;
typedef struct
{
unsigned n; // lap number
time t; // lap time
lap* next_ptr;
} lap;
public:
Stopwatch();
~Stopwatch();
void right_button(); // corresponds to start/stop/pause
void left_button(); // corresponds to lap/reset
private:
state cur_state;
lap* first_ptr;
}
Stopwatch::Stopwatch()
{
cur_state = UNSTARTED;
first_ptr = NULL;
}
Stopwatch::~Stopwatch()
{
// Destroy all laps
for (lap* thisptr = first_ptr; thisptr != NULL;)
{
lap* tempptr = thisptr;
thisptr = thisptr.next_ptr;
free (tempptr);
}
cur_state = FINISHED;
}
我还没有尝试编译任何东西,但在我继续之前我有几个问题。
(1)我释放链表的逻辑是否正确?我使用的程序是
(i)将thisptr设置为等于第一圈的指针。
(ii)虽然thisptr不是NULL,但是存储thisptr的副本,增加thisptr,然后释放副本指向的内存
这似乎是正确的,但对我来说再次指针仍然很棘手。
(2)我是否应该在使用NULL
之后设置等于free
的指针?在我到目前为止看到的所有代码示例中,当作者想要删除变量时,他们只是在其上使用free
。但我正在阅读这个人的指示http://www.cprogramming.com/tutorial/c/lesson6.html,然后他说要将其设为等于NULL
。我一直认为他的教程很好。
(3)当我在析构函数中引用namespace
时,是否需要使用lap*
运算符?即,我是否需要编写Stopwatch::lap*
而不是lap*
???我是否在我班级的正确位置声明了lap
结构?
答案 0 :(得分:1)
释放后将指针设置为NULL是没有必要的。可以建议如果在free()之后有用,代码将(应该......)立即崩溃并且更容易调试。 但是在C ++中你不应该需要它,因为你应该使用RAII并且永远不会拥有所有权的原始指针。
另请注意,在C ++中,您使用的是new
和delete
,而不是malloc
和free
。
你的循环不是很惯用,它看起来更像是一个while循环,因此它更具可读性:
lap* thisptr = first_ptr;
while(thisptr)
{
lap* tempptr = thisptr;
thisptr = thisptr.next_ptr;
free (tempptr);
}
逻辑似乎没问题。但是,如果不是一些家庭作业项目,你应该改变一些事情:
1)使用标准容器。如果你可以使用vector,那就用它吧。如果您的代码不适合矢量,请重新考虑使用矢量;-) 如果您以这种方式更改代码,则不需要析构函数:
class Stopwatch
{
...
typedef struct
{
unsigned n; // lap number
time t; // lap time
} lap;
...
private:
...
std::list<lap> laps; // Could you use vector?
}
注意,在C ++中,您通常以这种方式声明结构:
struct lap
{
unsigned n; // lap number
time t; // lap time
};
你可以在秒表课程中使用lap
来引用它。
2)C ++ 11提供日期/时间实用程序:
class Stopwatch
{
...
typedef std::chrono::system_clock::time_point time;
...
}
3)最好在构造函数中使用初始化列表:
Stopwatch::Stopwatch()
: cur_state(UNSTARTED)
{
}
对于C ++ 11中的简单案例,你甚至不需要构造函数:
class Stopwatch
{
...
private:
state cur_state = UNSTARTED;
...
}
另请注意,在析构函数中将状态更改为FINISHED
几乎没用,因为对象已被销毁。
答案 1 :(得分:0)
1)逻辑对我来说很好。我不能保证它会在没有尝试的情况下发挥作用,但这个想法是正确的。
2)如果指针对其他代码可见,最好在free
或delete
之后将其设置为null,这样每个人都会理解它不再指向任何有效的东西。但是,如果你是一个破坏者,无论如何一切都将要消失,那真的并不重要。但是,如果left_button中的重置功能实际上释放了列表,那么你需要在结束时将first_ptr设置为null。
3)不,当你在里面时,你不需要明确地扩展到你自己的班级。