Ctor, Dtor problem with handles

Jun 21, 2010 at 10:06am
Hi all,

I've created a class which uses the winapi. It has a number of constructors and a destructor. The class is called 'Thread'. When I use it like this:
Thread foobar(foobar, "foo", "bar");
it gives no problem. The class contains a handle of the thread. When the constructor is called it creates that handle and starts a new thread. To do that I use CreateThread from the winapi. The default constructor initializes the thread handle to 'INVALID_HANDLE_VALUE'. When the destructor is called, it uses CloseHandle to close the handle, but only if the handle doesn't equal to INVALID_HANDLE_VALUE. So what I believe should happen when you use it like this:
Thread test;
is that it creates no thread and on destruction, no handle gets closed.
However, when I do this:
1
2
Thread test;
test = Thread(foobar, "foo", "bar");

it runs the things in this order:
#1. It runs the default constructor.
#2. It runs the destructor with the three arguments.
#3. It runs the destructor, which I believe should be the dtor of the Thread created with the default constructor, but it contains the thread handle which is created by the ctor with the three arguments.
Then when they go out of scope:
#4. It calls the destructor with the same handle as in #3, so it closes that handle 2 times and that results in undefined behavior, in my case: an access violation error.

So my question is, why is the dtor of the same object called twice and the dtor of the 'empty' object none?
Last edited on Jun 21, 2010 at 10:14am
Jun 21, 2010 at 10:25am
I have created a simpler piece of code which illustrates my problem a bit better:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

using namespace std;

class Test
{
public:
	Test()
	{
		cout << "Ctor() called.\n";
		a = -1;
	}

	Test(unsigned short a)
	{
		cout << "Ctor(" << a << ") called.\n";
		Test::a = a;
	}

	~Test()
	{
		cout << "Dtor() called.\n";

		if (a != -1)
			cout << "a was " << a << '\n';
	}

private:
	int a;
};

int main ()
{
	Test test;
	test = Test(3);

	return 0;
}


This is the output:
Ctor() called.
Ctor(3) called.
Dtor called.
a was 3
Dtor called.
a was 3


But I expected this:
Ctor() called.
Ctor(3) called.
Dtor called.
Dtor called.
a was 3


Can anybody explain?
Jun 21, 2010 at 12:55pm
I know I can call the destructor within the default contructor, but isn't that a bit silly? I still don't know why that destructor is called twice from the post above here.
Jun 21, 2010 at 1:40pm
test = Thread( foobar, "foo", "bar" );

constructs a temporary object from which "test" gets assigned.

The first destructor call is to destroy this temporary after the assignment completes.
The second destructor call is to destroy test.

EDIT: and so two things. First, now you should understand why you need to write a copy constructor and
assignment operator, or, more likely, disable copying of Thread objects. (Does copying a thread object
create a second thread?) Second, the performance of the code you wrote is obviously terrible, which
should serve as a good explanation why it is better to write:

 
Thread test( foobar, "foo", "bar" );


(Many C programmers are used to the "declare on one line, initialize on another" idiom, which is NOT
the right way in C++)
Last edited on Jun 21, 2010 at 1:44pm
Jun 21, 2010 at 2:46pm
Ok thanks!
1
2
(Many C programmers are used to the "declare on one line, initialize on another" idiom, which is NOT
the right way in C++)

The reason why I did that was to illustrate what the problem was. In my code actually, it was part of a class, and not initialized, until an action by the user was taken. But I understand that I should have the class as non-copyable. I'll make a pointer to a thread object in the class, so I can control when the ctor and dtor is called.
Topic archived. No new replies allowed.