Is the following code legal, moral, and advisable?
#include <iostream>
class A {
private:
int a;
public:
A() : a(42) {}
~A() {
std::cout << "A's destructor called, a is " << a << std::endl;
}
};
class B : public A {
private:
int b;
public:
B() : b(666) {}
~B() {
std::cout << "B's destructor called, b is " << b << std::endl;
}
void go() { delete this; }
};
int main() {
B *b=new B();
b->go();
return 0;
}
Specifically, are B and A's destructors still permitted to access
their class' member variables after the this pointer has been deleted?
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome. 32 3112
Christopher Benson-Manica wrote: Is the following code legal, moral, and advisable?
#include <iostream>
class A { private: int a;
public: A() : a(42) {} ~A() { std::cout << "A's destructor called, a is " << a << std::endl; } };
class B : public A { private: int b;
public: B() : b(666) {} ~B() { std::cout << "B's destructor called, b is " << b << std::endl; } void go() { delete this; } };
int main() { B *b=new B(); b->go(); return 0; }
Specifically, are B and A's destructors still permitted to access their class' member variables after the this pointer has been deleted?
No, they aren't. But why would they need to? In your code, the destructors
are - just as usual - not called after the deletion, but as part of it.
And yes, you are allowed to delete an object in one of its member functions
as long as you make sure that nothing of it is accessed afterwards (i.e. in
your case, go() doesn't use any members of the object after the delete).
Whether 'delete this;' is a good design - well, I'd say that depends on
where and how the class is used.
* Christopher Benson-Manica: Is the following code legal, moral, and advisable?
Yes, whatever, no.
#include <iostream>
class A { private: int a;
public: A() : a(42) {} ~A() { std::cout << "A's destructor called, a is " << a << std::endl; } };
Intended for polymorphism but non-virtual destructor: bad.
class B : public A { private: int b;
public: B() : b(666) {} ~B() { std::cout << "B's destructor called, b is " << b << std::endl; } void go() { delete this; } };
Different lifetime management policies for A and B: bad.
B supports copying but requires dynamic allocation: bad.
I/o in non-i/o classes: bad.
int main() { B *b=new B(); b->go(); return 0; }
Specifically, are B and A's destructors still permitted to access their class' member variables after the this pointer has been deleted?
No, but they don't.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Christopher Benson-Manica wrote: Is the following code legal, moral, and advisable?
void B::go() { delete this; }
B *b=new B(); b->go();
C++ defines the act of returning from a method after its object deletes.
Whether its moral and advisable is a team and project decision. Some
frameworks encapsulate all their owner pointers, so the caller rarely sees
'new' and never sees 'delete'. Within this pattern, objects often must
delete themselves, and they notify all the linking pointers to NULL
themselves.
Now let's make your code illegal:
#include <iostream>
class B;
class A { private: int a;
B & m_b; public:
A(B &b) : a(42), m_b(b) {}
~A(); };
class B : public A {
public:
int b; public: B() : b(666) {} ~B() { std::cout << "B's destructor called, b is " << b << std::endl; } void go() { delete this; } };
A::~A() {
std::cout << "A's destructor called, a is " << a << std::endl;
std::cout << "B has already destructed, so accessing b is illegal "
<< m_b.b << std::endl;
}
int main() { B *b=new B(); b->go(); return 0; }
During destruction, the derived class sub-object destructs first, so
accessing its members is undefined during the split second before the entire
object's storage releases. In practice, our 'b' will most likely return the
correct value.
Specifically, are B and A's destructors still permitted to access their class' member variables after the this pointer has been deleted?
Their _own_ class's members, yes. They can also call methods. Destruction
happens just before releasing.
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Rolf Magnus <ra******@t-online.de> wrote: Whether 'delete this;' is a good design - well, I'd say that depends on where and how the class is used.
<ot>Well, what I have in mind is a class that takes a function pointer
and puts it on a background thread; when the function is complete, the
class will take care of deleting itself and stopping the thread.
Sound reasonable?</ot>
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Alf P. Steinbach <al***@start.no> wrote: Yes, whatever, no.
Why do I feel like I'm conversing with an elf...?
<ot>I don't mind playing the role of Merry/Pippin - I really do look
like a hobbit :-)</ot>
Different lifetime management policies for A and B: bad.
So you're saying that if a given class never deletes itself, that no
subclass of that class should do so either...?
B supports copying but requires dynamic allocation: bad.
Is this a "Rule of Three" violation?
I/o in non-i/o classes: bad.
Explain? Please? :-)
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Christopher Benson-Manica wrote: Well, what I have in mind is a class that takes a function pointer and puts it on a background thread; when the function is complete, the class will take care of deleting itself and stopping the thread. Sound reasonable?
Objects that wrap Win32 windows often respond to WM_CLOSE with 'delete
this'.
The distinction is these systems have an asynchronous event queue, so the
event triggering suicide comes from outside normal control flow.
But please don't thread if there are any alternatives!
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Christopher Benson-Manica wrote: Elf P. Steinbach wrote: Different lifetime management policies for A and B: bad.
So you're saying that if a given class never deletes itself, that no subclass of that class should do so either...?
I disagree. Let's apply the Liskov Substitution Principle.
If 'go()' were virtual and inherited, then users of A * p might call
p->go(), then expect p to remain valid. When p really points to a B, p->go()
would delete it. This would force the caller to become aware of which
subtype of A it used. This violates LSP, which states that child classes
should not surprise clients of parent classes who want to remain unaware
they are using the child class.
However, 'go()' is not virtual. Users of A cannot call 'go()', and users of
B cannot believe they have an A. So LSP does not apply, and there are no
surprises.
There are situations where all members of an inheritance graph should use
the same creation strategy. For example, OO designs often revolve around big
sessile objects that should never copy, and little value objects that copy
around freely. But I think this one 'go()' is the exception that proves the
rule. B supports copying but requires dynamic allocation: bad.
Is this a "Rule of Three" violation?
Bleah. He's just nitpicking. You did not turn off B's copy constructor.
And B does not "require" dynamic allocation, because you could create B on
the stack and then decline to call go(). I/o in non-i/o classes: bad.
Explain? Please? :-)
Nitpicking again. You wrote 'cout' inside a class that should not surprise
clients with a side-effect that the user can see. Big friggin' deal.
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Christopher Benson-Manica wrote: Rolf Magnus <ra******@t-online.de> wrote:
Whether 'delete this;' is a good design - well, I'd say that depends on where and how the class is used.
<ot>Well, what I have in mind is a class that takes a function pointer and puts it on a background thread; when the function is complete, the class will take care of deleting itself and stopping the thread. Sound reasonable?</ot>
If the calling thread never needs any data of the called thread (maybe an
exit status or some calculated data stored in the thread object), yes.
"Christopher Benson-Manica" <at***@nospam.cyberspace.org> wrote in message
news:d9**********@chessie.cirr.com... Is the following code legal, moral, and advisable?
Hmmm... what exactly would "immoral" C++ code be? :-)
(Sorry, couldn't resist.)
-H
Phlip <ph*******@yahoo.com> wrote: Elf P. Steinbach wrote:
:-)
I disagree. Let's apply the Liskov Substitution Principle.
I feel better that I apparently inadvertently followed it, but I
appreciate knowing that it exists in any case.
Bleah. He's just nitpicking. You did not turn off B's copy constructor.
I don't mind nitpicks, if I understand the reasoning behind them.
And B does not "require" dynamic allocation, because you could create B on the stack and then decline to call go().
B would require some documentation letting users know how it was
intended to be used, however. Maybe the way to do it (what I really
want to do) would be to wrap the class that destroys itself in a class
that doesn't care, making it impossible to misuse it?
Nitpicking again. You wrote 'cout' inside a class that should not surprise clients with a side-effect that the user can see. Big friggin' deal.
Again, I don't mind nitpicks, especially since I know I'm living in a
bubble of sorts at my present place of employement...
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Phlip <ph*******@yahoo.com> wrote: But please don't thread if there are any alternatives!
Why do you say that? (non-rhetorical question)
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Christopher Benson-Manica wrote: Phlip wrote:
But please don't thread if there are any alternatives!
Why do you say that? (non-rhetorical question)
I research GUI architectures. One of the most common anti-patterns in this
space is "that button takes too long, and locks up the GUI while it runs, so
we made the button launch a thread".
Because I don't research OS kernels, embedded software, or other primitive
spaces that need threads to get anything done, I have never seen a situation
improved by a thread. Throwing a thread at a simple problem is worse than
'goto'. If a button starts a process that takes too long, the process itself
needs a better architecture.
Suppose I write a function that finds each file on your hard drive, and
inspects it for virii. The main work loop recurses, following the folders
like this:
click the button
open a folder
open a sub folder
read a file
is it infected?
That's going to take forever. While the button serves its click event, the
main GUI event queue cannot dispatch other messages, so the user perceives a
locked-up GUI.
Now let's upgrade this design, to decouple it and make it event driven:
click the button
change the button label to "cancel scan"
post a WM_TIMER message
on WM_TIMER message
fetch the next file name
if there's a next file
is it infected?
post a WM_TIMER message
The part "fetch the next file name" now uses a linked list of opened folders
to pull out the next one. This strategy decouples the act of traversing the
folder hierarchy from the act of inspecting for virii. Decoupling is good.
This strategy uses no threads, and uses a windows timer to cleanly start and
stop the scan. (Stop the scan by cancelling the current WM_TIMER message.)
The strategy is "event driven" because it doesn't store state in the current
location of control flow. The recursive function stores the current folder
state locally, on the stack, and coupled to the file scanner. The event
driven system stores the current folder state explicitely in a linked list.
This, in turn, makes the folder traversal system modular and reusable.
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Phlip wrote: Christopher Benson-Manica wrote:
Phlip wrote:
> But please don't thread if there are any alternatives! Why do you say that? (non-rhetorical question)
I research GUI architectures. One of the most common anti-patterns in this space is "that button takes too long, and locks up the GUI while it runs, so we made the button launch a thread".
Because I don't research OS kernels, embedded software, or other primitive spaces that need threads to get anything done, I have never seen a situation improved by a thread. Throwing a thread at a simple problem is worse than 'goto'. If a button starts a process that takes too long, the process itself needs a better architecture.
I agree with Philip. Threads introduce a another level of complexity, thus
overstraining most developers. You have to change your way of thinking
before you can get a real gain by using threads.
Suppose I write a function that finds each file on your hard drive, and inspects it for virii. The main work loop recurses, following the folders like this:
click the button open a folder open a sub folder read a file is it infected?
That's going to take forever. While the button serves its click event, the main GUI event queue cannot dispatch other messages, so the user perceives a locked-up GUI.
Now let's upgrade this design, to decouple it and make it event driven:
click the button change the button label to "cancel scan" post a WM_TIMER message
on WM_TIMER message fetch the next file name if there's a next file is it infected? post a WM_TIMER message
The part "fetch the next file name" now uses a linked list of opened folders to pull out the next one. This strategy decouples the act of traversing the folder hierarchy from the act of inspecting for virii. Decoupling is good. This strategy uses no threads, and uses a windows timer to cleanly start and stop the scan. (Stop the scan by cancelling the current WM_TIMER message.)
The strategy is "event driven" because it doesn't store state in the current location of control flow. The recursive function stores the current folder state locally, on the stack, and coupled to the file scanner. The event driven system stores the current folder state explicitely in a linked list. This, in turn, makes the folder traversal system modular and reusable.
Of course its necessary to obtain the linked list of files (in the same
manner). And we silently assume, that "is it infected" will never block
(block from the point of view of the user). If we start another thread or
process to do the scanning, we would be able to kill it immediately
whenever the frustrated user hits the cancel button.
Every solution has its drawbacks (and sometimes some advantages).
Mathias
PS: sorry for being OT.
Phlip <ph*******@yahoo.com> wrote:
(Moving to comp.programming.threads - if you don't read that group,
come back to clc++...) Because I don't research OS kernels, embedded software, or other primitive spaces that need threads to get anything done, I have never seen a situation improved by a thread. Throwing a thread at a simple problem is worse than 'goto'. If a button starts a process that takes too long, the process itself needs a better architecture.
Well, my specific intention for this thread is for it to take care of
caching the contents of a file in memory as my program is starting.
The main thread can't wait that long, because the program is a Windows
service and the service manager isn't willing to wait forever for my
program to start. I know I could do this other ways, but is there
really a big disadvantage to spawning a thread to handle the caching
of this file?
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Christopher Benson-Manica wrote: B would require some documentation letting users know how it was intended to be used, however. Maybe the way to do it (what I really want to do) would be to wrap the class that destroys itself in a class that doesn't care, making it impossible to misuse it?
Ding! Objects should be easy to use right and hard to use wrong.
About "documentation", try some test cases that show each object's normal
lifecycle. Class users (including yourself) will be unlikely to deviate. Nitpicking again. You wrote 'cout' inside a class that should not
surprise clients with a side-effect that the user can see. Big friggin' deal.
Again, I don't mind nitpicks, especially since I know I'm living in a bubble of sorts at my present place of employement...
How DARE you write 'cout' inside a non-IO class?!!
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Mathias Waack wrote: Of course its necessary to obtain the linked list of files (in the same manner). And we silently assume, that "is it infected" will never block (block from the point of view of the user). If we start another thread or process to do the scanning, we would be able to kill it immediately whenever the frustrated user hits the cancel button. Every solution has its drawbacks (and sometimes some advantages).
"Is it infected", in turn, runs a list of potential virii, so we have
another spot to decouple.
From here, event-driven architectures are overwhelmingly easy to switch to
use threads, because the places between the events, for other activities,
are also good places for semaphores. But this doesn't work the opposite way.
Poorly architected systems might be hard to convert from threads to events.
So, either way, focus on good architecture.
Christopher Benson-Manica wrote:
Well, my specific intention for this thread is for it to take care of caching the contents of a file in memory as my program is starting. The main thread can't wait that long, because the program is a Windows service and the service manager isn't willing to wait forever for my program to start. I know I could do this other ways, but is there really a big disadvantage to spawning a thread to handle the caching of this file?
Short term, no. Removing this thread won't force the architecture to
improve.
Long term, use ReadFileEx() in asynchronous mode. If you need notification
that the file arrived, you can multiplex the file event semaphore in with
the window messages using MsgWaitForMultipleObjects().
Or start a window timer that wakes up and reads a small chunk of the file.
The file system will buffer the real file asynchronously, behind these
reads, meaning they shouldn't block the GUI.
Notice the tutorials tend to teach threading _before_ they teach these
high-powered methods to cleanly avoid threads...
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Phlip <ph*******@yahoo.com> wrote: Long term, use ReadFileEx() in asynchronous mode. If you need notification that the file arrived, you can multiplex the file event semaphore in with the window messages using MsgWaitForMultipleObjects().
Well, I guess I should have chosen my words more carefully - the file
has the contents of a list of data structures, each of which needs to
be parsed before the program can begin its real work.
Notice the tutorials tend to teach threading _before_ they teach these high-powered methods to cleanly avoid threads...
Yes, I do notice that, and I'll remember them (hopefully) next time I
do GUI work :-)
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Phlip <ph*******@yahoo.com> wrote: How DARE you write 'cout' inside a non-IO class?!!
Well, neither I nor my coworkers much care, but presumably there are
places and bosses where that is the standard, so it's worth at least
being thus forewarned...
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Christopher Benson-Manica wrote: How DARE you write 'cout' inside a non-IO class?!!
Well, neither I nor my coworkers much care, but presumably there are places and bosses where that is the standard, so it's worth at least being thus forewarned...
Ookay. Read /Design Patterns/. It sounds like your colleagues are not even
at this level yet... Long term, use ReadFileEx() in asynchronous mode. If you need
notification that the file arrived, you can multiplex the file event semaphore in
with the window messages using MsgWaitForMultipleObjects().
Well, I guess I should have chosen my words more carefully - the file has the contents of a list of data structures, each of which needs to be parsed before the program can begin its real work.
Are you trying to read blocks in one thread and parse in another? If so,
there's no point. The hard drive controller reads file tracks while the disk
is spinning, so their data blocks are ready each time you call ReadFile().
So you already have blocks reading in one thread and parsing in another.
We are nearing the concept "Premature optimization" here...
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Phlip <ph*******@yahoo.com> wrote: Ookay. Read /Design Patterns/. It sounds like your colleagues are not even at this level yet...
Well, on the bright side, it's sitting within easy reach on this desk.
Unfortunately there's very little designing or redesigning going on
relative to the amount of maintaining...
Are you trying to read blocks in one thread and parse in another? If so, there's no point. The hard drive controller reads file tracks while the disk is spinning, so their data blocks are ready each time you call ReadFile(). So you already have blocks reading in one thread and parsing in another.
No, I'm reading and parsing in one thread while the rest of the
initialization continues courtesy of the service control manager.
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
* Phlip: * Christopher Benson-Manica:
* Alf P. Steinbach wrote: Different lifetime management policies for A and B: bad.
So you're saying that if a given class never deletes itself, that no subclass of that class should do so either...?
I disagree.
... there are no urprises.
Sorry, the analysis is flawed.
A B-object may be terminated unexpectedly when it is used in place of
an A, under A assumptions.
For example, the code holding a presumed A (really a B) may be unaware
that some other, event-driven code holds a pointer to the B object as
a B, and terminates it...
Without analysing your analysis in detail I think the flaw is perhaps an
assumption that _all_ code must be either "B-aware" or not.
That's not the case. B supports copying but requires dynamic allocation: bad.
Is this a "Rule of Three" violation?
Bleah. He's just nitpicking. You did not turn off B's copy constructor.
It's an important nitpick.
If a B-object is inadvertently copied, the result is undefined.
That means a possible later catastrophic error that nobody understand
at all.
And B does not "require" dynamic allocation, because you could create B on the stack and then decline to call go().
Well, the Titanic was a safe ship, because you could refrain from bording. I/o in non-i/o classes: bad.
Explain? Please? :-)
Nitpicking again. You wrote 'cout' inside a class that should not surprise clients with a side-effect that the user can see. Big friggin' deal.
Affects reusability and not the least, complicates the code (in general).
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Phlip wrote: Now let's upgrade this design, to decouple it and make it event driven:
click the button change the button label to "cancel scan" post a WM_TIMER message
on WM_TIMER message fetch the next file name if there's a next file is it infected? post a WM_TIMER message
The part "fetch the next file name" now uses a linked list of opened folders to pull out the next one. This strategy decouples the act of traversing the folder hierarchy from the act of inspecting for virii. Decoupling is good. This strategy uses no threads, and uses a windows timer to cleanly start and stop the scan. (Stop the scan by cancelling the current WM_TIMER message.)
The strategy is "event driven" because it doesn't store state in the current location of control flow. The recursive function stores the current folder state locally, on the stack, and coupled to the file scanner. The event driven system stores the current folder state explicitely in a linked list. This, in turn, makes the folder traversal system modular and reusable.
How would you handle multiple different asynchronous actions with WM_TIMER
messages which may or may not be invoked concurrently? You'd have to multiplex
them somehow and guarantee fairness in execution.
--
Joe Seigh
When you get lemons, you make lemonade.
When you get hardware, you make software.
Christopher Benson-Manica wrote: Is the following code legal, moral, and advisable?
#include <iostream>
class A { private: int a;
public: A() : a(42) {} ~A() { std::cout << "A's destructor called, a is " << a << std::endl; } };
class B : public A { private: int b;
public: B() : b(666) {} ~B() { std::cout << "B's destructor called, b is " << b << std::endl; } void go() { delete this; } };
int main() { B *b=new B(); b->go(); return 0; }
Yes, but you must be *very* careful. See the FAQ for details.
Kristo
Christopher Benson-Manica wrote: Phlip <ph*******@yahoo.com> wrote:
(Moving to comp.programming.threads - if you don't read that group, come back to clc++...)
Because I don't research OS kernels, embedded software, or other primitive spaces that need threads to get anything done, I have never seen a situation improved by a thread. Throwing a thread at a simple problem is worse than 'goto'. If a button starts a process that takes too long, the process itself needs a better architecture.
Well, my specific intention for this thread is for it to take care of caching the contents of a file in memory as my program is starting. The main thread can't wait that long, because the program is a Windows service and the service manager isn't willing to wait forever for my program to start. I know I could do this other ways, but is there really a big disadvantage to spawning a thread to handle the caching of this file?
No, not "a big disadvantage".
Threads used correctly (it takes some practice) can enable
quite complex & responsive applications. The "threads good
or bad" discussion depends on many complex factors; like all
tools, they have their uses, but they (nor anything else) are
not a "silver bullet".
Larry
Joe Seigh wrote: How would you handle multiple different asynchronous actions with WM_TIMER messages which may or may not be invoked concurrently? You'd have to
multiplex them somehow and guarantee fairness in execution.
Besides WM_TIMER comes with a payload integer to distinguish message
streams?
At some point you give up and add a thread. You use it as carefully and
judiciously as possible. Don't use threads like a baby who has just learned
to use a hammer, and thinks everything looks like a nail.
(Note I'm busting on languages that make threads "easy"...)
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
Phlip wrote: Joe Seigh wrote:
How would you handle multiple different asynchronous actions with WM_TIMER messages which may or may not be invoked concurrently? You'd have to
multiplex
them somehow and guarantee fairness in execution.
Besides WM_TIMER comes with a payload integer to distinguish message streams?
At some point you give up and add a thread. You use it as carefully and judiciously as possible. Don't use threads like a baby who has just learned to use a hammer, and thinks everything looks like a nail.
(Note I'm busting on languages that make threads "easy"...)
Well, it's a nice trick I suppose if you don't have threads. Otherwise it seems
a bit contrived and makes things more complicated than they need to be. One of
the reasons for threading is modularization as much as for asynchronicity or
concurrency. It's to make things simpler. I think the main culprit is not so well
thought out OO design and design patterns which cause more problems than they
solve. The "anti-patterns" if you will. I haven't messed with GUI programming
lately but the early MVC implementations in Java were atrocious and a major pain
to work with. Probably if you had the GUI primatives designed by people who
understood threading a little better and knew the thread design patterns useful
for keeping out of trouble, not so many people would find multi-threaded GUI
programming quite so traumatic. And c.p.t. wouldn't have so many posts requesting
information on deadlock detection (invariably by people doing OO GUI programming).
--
Joe Seigh
When you get lemons, you make lemonade.
When you get hardware, you make software.
Christopher Benson-Manica wrote: Well, my specific intention for this thread is for it to take care of caching the contents of a file in memory as my program is starting. The main thread can't wait that long, because the program is a Windows service and the service manager isn't willing to wait forever for my program to start. I know I could do this other ways, but is there really a big disadvantage to spawning a thread to handle the caching of this file?
Flirting with Deceased Equine Flaggelation Mode, but...
In your case you are a service, not a simple app, so your program already
solves concurrency issues, so one more shouldn't hurt.
But note that Win32 services uses the GetMessage() DispatchMessage() event
loop, so my multiplexing solution would still work.
Another principle here is to push as much work, creativity, and risk down to
the OS as possible. ReadFileEx().
Joe Seigh wrote:
Well, it's a nice trick I suppose if you don't have threads.
Per the other posts: An event driven architecture is good whether or not you
thread, and threading should not be used to avoid supplying the good
architecture.
Otherwise it seems a bit contrived and makes things more complicated than they need to be.
One of the reasons for threading is modularization as much as for asynchronicity
or concurrency. It's to make things simpler.
And threads can break encapsulation, and force an object in one thread to
become aware of the private details and activities of an object in another
thread, waiting for it to release a semaphore.
(Before the denizens of cpt think I'm some kind of anti-threading zealot
newbie, I grew up developing for AmigaOS, which works like a modern embedded
system. Threads are necessary, and one false move with threads would send
the CPU into FIREWORKS_DISPLAY mode.)
I think the main culprit is not so well thought out OO design and design patterns which cause more problems than
they solve. The "anti-patterns" if you will. I haven't messed with GUI
programming lately but the early MVC implementations in Java were atrocious and a
major pain to work with. Probably if you had the GUI primatives designed by people
who understood threading a little better and knew the thread design patterns
useful for keeping out of trouble, not so many people would find multi-threaded
GUI programming quite so traumatic.
Are you implying that there are GUI architectures that thread each input
event as the _default_??
And c.p.t. wouldn't have so many posts requesting information on deadlock detection (invariably by people doing OO GUI programming).
I rest my case.
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
"Phlip" <ph*******@yahoo.com> schrieb: click the button open a folder open a sub folder read a file is it infected?
click the button change the button label to "cancel scan" post a WM_TIMER message
on WM_TIMER message fetch the next file name if there's a next file is it infected? post a WM_TIMER message
The part "fetch the next file name" now uses a linked list of opened folders to pull out the next one. This strategy decouples the act of traversing the folder hierarchy from the act of inspecting for virii. Decoupling is good. This strategy uses no threads, and uses a windows timer to cleanly start and stop the scan. (Stop the scan by cancelling the current WM_TIMER message.)
No, I cannot agree with this. This is not a real decoupling. The
former thread is indeed decoupled from the GUI and perhaps the GUI can
really remain active but there's still a new coupling on another
controlling instance (in this case a timer). In my opinion this timer
destroys the whole algorithm by cutting it into infinitesimal small
pieces. What if I want to execute it at once? I hate destroyed
algorithms especially if they are complicated. Good luck for debugging
this!
Some years ago I implemented an editor control supporting syntax
highlighting. After some weeks of development I found it a good idea
to use a background thread for the parsing and coloring algorithm
itself because opening a large file could take a really long time.
During this time my control did display the text in black and white,
some seconds later the color came along. Every pressed key did start
or reset a timer and after a short while the thread was executed again
to show the text in perhaps new colors. Still today I think this was a
good reason to use a thread in a GUI.
T.M.
Torsten Mueller wrote: No, I cannot agree with this. This is not a real decoupling. The former thread is indeed decoupled from the GUI and perhaps the GUI can really remain active but there's still a new coupling on another controlling instance (in this case a timer). In my opinion this timer destroys the whole algorithm by cutting it into infinitesimal small pieces. What if I want to execute it at once? I hate destroyed algorithms especially if they are complicated.
A major metric for decoupling is testability. The "before" pattern cannot
test the folder recursion system isolated from the file scanner. The "after"
pattern can test the WM_TIMER, the file scanner, and the folder recursion,
all three isolated from each other.
Good luck for debugging this!
Uh, I actually implemented the "after" pattern, using Test-Driven
Development, and when I was finished adding tests it had no bugs. I often
used the debugger to step thru the code and watch it work, but I never
_needed_ to use the debugger.
If changing requirements caused a bug, in the future, and if tests did not
catch it, the test cases would make an excellent platform for debugging (or
even just for trace statements) to detect the problem. Then new tests on the
problem, and the existing tests, would prevent the bug fix from creating new
bugs.
On review, the client liked the code structure and my coding style.
So, no luck will ever be required to debug my implementation of this
pattern.
Threads make bug repression a nightmare because race conditions might behave
in simple tests different from in production.
Some years ago I implemented an editor control supporting syntax highlighting. After some weeks of development I found it a good idea to use a background thread for the parsing and coloring algorithm itself because opening a large file could take a really long time.
If you need to eat a sandwich in one hand and drive with the other, thread.
During this time my control did display the text in black and white, some seconds later the color came along. Every pressed key did start or reset a timer and after a short while the thread was executed again to show the text in perhaps new colors. Still today I think this was a good reason to use a thread in a GUI.
How does VS6 or VS7 highlight its syntax in realtime, without a refresh
period?
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand
"Phlip" <ph*******@yahoo.com> schrieb: I often used the debugger to step thru the code and watch it work, but I never _needed_ to use the debugger.
You never had to explain an application somebody else wrote, perhaps a
person using a strange programming style (this is because normally he
was a lisp programmer), speaking another native language and nobody
has seen him for years?
If changing requirements caused a bug, in the future, and if tests did not catch it, the test cases would make an excellent platform for debugging (or even just for trace statements) to detect the problem. Then new tests on the problem, and the existing tests, would prevent the bug fix from creating new bugs.
No. You cannot guarantee a software quality by tests. I always have to
fight against this opinion (especially managers do think like this).
Tests are nothing but an emergency break, something one can use too if
nothing else has left (especially if the software's design and
implementation do not guarantee it's quality).
On review, the client liked the code structure and my coding style.
And who is the client? A customer? I mean - a user?
Threads make bug repression a nightmare because race conditions might behave in simple tests different from in production.
Normally threads are testable non-threaded! In most cases you can
write down an entire algorithm, debug it, test it, optimize it, and
then you can say, this function runs as a thread now. OK, if you have
several concurrent threads it would be more complicated.
How does VS6 or VS7 highlight its syntax in realtime, without a refresh period?
These applications do support just a few hard coded languages. My
editor control was open to support *any* language having been defined
by semantic rules in an initialization file. And I supported nested
comments (this takes a lot of time more than just C/C++ comments). If
you take a look upon Visual Assist (coloring function names, class
names, matching brackets ... in Visual Studio) you will see threading
is surely needed for background parsing and coloring of a text.
T.M.
Torsten Mueller wrote: Phlip schrieb:
I often used the debugger to step thru the code and watch it work, but I never _needed_ to use the debugger. You never had to explain an application somebody else wrote, perhaps a person using a strange programming style (this is because normally he was a lisp programmer), speaking another native language and nobody has seen him for years?
That's out of context. I described a project I wrote from scratch.
If someone gives you a program built by Debugger-Driven Development, you
have no choice but to pick up where they left off.
No. You cannot guarantee a software quality by tests.
Of course not. But you sure as hell can avoid long bug hunts.
I always have to fight against this opinion (especially managers do think like this). Tests are nothing but an emergency break, something one can use too if nothing else has left (especially if the software's design and implementation do not guarantee it's quality).
So why not write tests before writing the tested code? That makes them
efficient to write, turning them from a backup situation into a way to
propel development. On review, the client liked the code structure and my coding style.
And who is the client? A customer? I mean - a user?
A programmer who must maintain that code. Threads make bug repression a nightmare because race conditions might behave in simple tests different from in production.
Normally threads are testable non-threaded! In most cases you can write down an entire algorithm, debug it, test it, optimize it, and then you can say, this function runs as a thread now. OK, if you have several concurrent threads it would be more complicated.
Things which are hard to test should be avoided. That's a sign they bring
too much complexity.
If they are, in fact, the simplest spot between even more complexity, tests
can detect this situation, and can reinforce the fixes.
--
Phlip http://www.c2.com/cgi/wiki?ZeekLand This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Peter King |
last post by:
if you assign multiple classes in order to keep your classes generic
e.g
..classA { position.absolute; left:5 top:5 height:200 width:800 }
..classB { background-color: red}
..classC {...
|
by: Stefan Strasser |
last post by:
why is delete an expression and not a statement? (in my draft copy of
the standard).
I was about to ask the same question about "throw" but found an
expression case of throw("return boolvalue ? 5...
|
by: aden |
last post by:
I have read the years-old threads on this topic, but I wanted to
confirm what they suggest. . .
Can the this pointer EVER point to a type different from the class that
contains the member...
|
by: gary |
last post by:
Hi,
We all know the below codes are dangerous:
{
int *p = new int;
delete p;
delete p;
}
And we also know the compilers do not delete p if p==NULL.
So why compilers do not "p = NULL"...
|
by: papaja |
last post by:
Hi,
I posted this on asp.net forums already, but nobody answered it. Here
is direct link: http://forums.asp.net/1124640/ShowPost.aspx.
Here is the question:
I'm using this code in delete...
|
by: Bob Tinsman |
last post by:
This problem shows up in Firefox 1.5.0.1 and Rhino 1.6R2.
I've found that if I have an XML node expression that ends in a filter,
I can't use it with the delete operator. In the following...
|
by: mkaushik |
last post by:
Hi everyone,
Im just starting out with C++, and am curious to know how "delete
<pointer>", knows about the number of memory locations to free.
I read somewhere that delete frees up space...
|
by: WaterWalk |
last post by:
Hello. The question about "deleting this inside the class's member
function" is discussed many times in this group and in the "C++
FAQs". But I still have two more questions.
1. Take the...
|
by: Daniel Pitts |
last post by:
I have std::vector<Base *bases;
I'd like to do something like:
std::for_each(bases.begin(), bases.end(), operator delete);
Is it possible without writing an adapter? Is there a better way? Is...
|
by: tvnaidu |
last post by:
I compiled tinyxml files (.cpp files) and when I am linking to create final exe in Linux, I am getting lot of errors saying "undefiend reference" to "operator new" and "delete", any idea?.
...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
|
by: ryjfgjl |
last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
| |