Re: I don't have to tell you...
"Joshua Maurice" <joshuamaurice@gmail.com> wrote in message
news:9e1954a5-d231-493d-bc17-9b55af272335@c3g2000yqd.googlegroups.com...
On Nov 28, 12:29 pm, Pavel
<pauldontspamt...@removeyourself.dontspam.yahoo> wrote:
BTW, I just found the reference to this article of Scott Meyers ibid in
Wikipedia:http://www.artima.com/cppsource/nevercall.html. I think
logically those who agree with this his opinion should agree to us
(Howard and myself) as well: what a point in having a "safety feature"
that is recommended to be used .. never?
I say "logically" because Scott himself would apparently disagree:
"... That's how every part of C++ will treat it, and the treatment makes
sense: the BuyTransaction-specific parts of the object haven't been
initialized yet, so it's safest to treat them as if they didn't exist".
I, on the other hand, cannot see a big difference between calling any
function within a constructor (where some parts of an object may not
have been initialized yet) and calling a virtual function ibid. I
believe that treating the derived-class object as "non-existing" before
entering its construction function is an arbitrary and not very useful
choice of the Standard.
Simple example.
//
#include <string>
struct F
{
virtual std::string const& name() const =0;
};
struct G : F
{
std::string name_;
virtual std::string const& name() const { return name_; }
};
//
Now, if I wrote that sample correctly, let's look at F and G. Suppose
F's constructor calls name() for debugging purposes. If it were to go
to the most derived but not yet constructed object G, then it would
return a reference to the not yet construct string sub-object, and any
attempt to use it would probably crash because it's not initialized:
the internal pointer of std::string would point to garbage and
dereferencing it would crash or be equivalently bad. Moreover, if
instead of string you had an object with virtual functions, then
calling anything on it would be bad because it's virtual table has not
yet been set up, so calling any virtual function on the sub-object
would horribly fail.
FWIW, I have seen this type of error quite a few times when I am looking at
thread wrapper's implemented as a base class. The base class run's the
thread from the damn constructor, which in turn calls a pure virtual
function to invoke the derived class thread entry point. This is a major
race-condition. If the thread runs and calls that virtual function BEFORE
the derived class is FULLY constructed, BOOOOM! You're dead!
Here is a quick example:
__________________________________________________________________
#include <sched.h>
#include <pthread.h>
#include <cstdio>
#define YIELD sched_yield(), sched_yield(), sched_yield
extern "C" void* thread_base_entry(void*);
class thread_base
{
pthread_t m_tid;
virtual void on_entry() = 0;
friend void* thread_base_entry(void*);
public:
thread_base()
{
pthread_create(&m_tid, NULL, thread_base_entry, this);
YIELD(); // LOL!
}
void join()
{
pthread_join(m_tid, NULL);
}
};
void* thread_base_entry(void* state)
{
thread_base& this_ = *static_cast<thread_base*>(state);
this_.on_entry();
return NULL;
}
class foo : public thread_base
{
void on_entry()
{
std::puts("Hello from foo!");
}
public:
foo()
{
std::puts("Hello from foo's CTOR!");
}
};
int
main()
{
{
foo f;
f.join();
}
return 0;
}
__________________________________________________________________
This will probably crash, then again it might not because the whole thing is
a giant race condition.
What a MESS!
:^o
[...]