Re: C++ in kernel (was Re: exception in a device driver)

Khimenko Victor (khim@sch57.msk.ru)
Sat, 16 Jan 1999 23:11:36 +0300 (MSK)


In <19990116134342.E4232@perlsupport.com> Chip Salzenberg (chip@perlsupport.com) wrote:
CS> According to Khimenko Victor:
>> In <19990115230842.C767@perlsupport.com> Chip Salzenberg (chip@perlsupport.com) wrote:
>> CS> According to Khimenko Victor:
>> >> Even two constructs like
>> >> A. someclass var(1);
>> >> B. someclass var=1;
>> >> are NOT equal!
>>
>> CS> Yes, and ... ? Initialization and assignment are entirely different
>> CS> animals in C++. Anyone who doesn't know that isn't ready to _read_
>> CS> C++ code, much less write it.
>>
>> Uh, oh, bummmm. This mean that YOU are one who "isn't ready to _read_ C++ code,
>> much less write it". (Hint: there are NO assignment in BOTH constructs!).

CS> You are mistaken, again. Statement (B) is default construction of
CS> var, followed by construction of a temporary "someclass(1)", followed
CS> by assignment of that temporary to var, followed by destruction of the
CS> temporary. The compiler may elide the contruction and destruction of
CS> the temporary under many circumstances; but the semantics are clear
CS> nonetheless.

Great ! And you still think that this language is usefull for anything ?
When even expirienced programmer (I think that you are expirienced C++
programmer :-) could do stupid mistakes in trivial cases like that ?

-- cut --
class test {
int x;
public:
test(int i) : x(i) {}
test(const test& t) : x(t.x) {}
private:
test& operator=(const test& t) { x=t.x; return *this; }
};

void main() {
test A=1;
A=2;
}
-- cut --

Try to compile this program. "test A=1;" will be accepted while "A=2;" will be
rejected. And if you think that all you compilers are broken then think about
-- cut --
int i;
int &r=i;
-- cut --
and eat shit :-)) (I'm does not have latest ANSI C++ standard handy but if
now "int &r=i;" is not assignment while "someclass var=1;" is assignment then
C++ is now even more cryptic then it used to be)...

>> >> If you'll use objects you are tied to VERY LIMITED C++ object model.
>>
>> CS> That's a feature, not a bug. C++'s object model is limited to
>> CS> features that have efficient implementation and which penalize only
>> CS> those who use them.
>>
>> Yes, but why use it at all ?

CS> Static type checking with knowledge of inheritance; forced
CS> construction and destruction; convenience. (C already has adequate
CS> static type checking if you use composition instead of inheritance.)

Forced destruction with temporary variables is biggest nightmare of C++
(something like (string("a")+string("b")).c_str and such) while forced
contruction is not so big win. What about convenience... Just discussed
example is enough to prove otherwise IMO. Language so cryptic that even
expirienced programmer could do mistakes even in simpliest contructions
could not inprove convenience. No way.

>> CS> Base *target = new Derived1;
>> CS> // begin transmogrification
>> CS> void *p = dynamic_cast<void *>(target);
>> CS> target->~Base();
>> CS> target = new (p) Derived2;
>> CS> // end transmogrification
>>
>> CS> Tadaa, all done. Only requirement is that the new class be no larger
>> CS> than the old one -- same as C. :-)
>>
>> Unfortunatelly this is
>> 1. Not feature of C++ but feature of GNU C++ (i.e.: non-portable; still most
>> implementation will work Ok here).

CS> You are mistaken, again. This is 100% ANSI C++. I wrote it with the
CS> ANSI standard open in another window.

TEXT is 100% ANSI C++. Workability -- implementation specific...
sizeof(Derived2) <= sizeof(Derived1) is NOT enough. UNLIKE C ! Since even if
sizeof(Derived2) <= sizeof(Derived1) it's NOT guaranteed that
void * operator new (size_t size, void *p placement) throw()
will be called with size_t < sizeof(Derived1) !!! Think about implementation
where each object not on stack or in array is prefixed with information for
profiler, for example. So this could be considered as non-portable low-level
hack at most :-)) GREAT for portable program like perl !!!

>> 2. Since target could change value after such "change nature of your class"
>> so it's not exactly change nature of your class -- more like optimization
>> of new/delete call.

CS> It is _exactly_ changing the nature of an object (not a class, but I
CS> think that's just a typo on your part). Consider that we may choose
CS> to define a constructor for Derived2 that omits the initialization of
CS> member variables, thus inheriting previous values from Derived1.

Of course it was type. I mean changing nature of object, not class (hm, hm,
changing nature of class is possible in C as well :-). This is NOT change of
object nature. As result we could get different object with different address...
When I refer to "change nature of your object" I refer to ability to get new
object in the same place of memory with different behaviour (most OOP-languages
does not have this ability but it's easily doable with artifactual
objects/classes in C). Now take a look:

-- cut --
#include <iostream>
#include <memory>

struct Base {
int x;
Base(int _x) : x(_x) { }
virtual foo() { std::cout << "Base::foo, x= " << x << endl; }
virtual ~Base() { }
};

struct OtherClass {
int z;
OtherClass(int _z) : z(_z) { }
virtual bar() { std::cout << "OtherClass::bar, z= " << z << endl; }
virtual ~OtherClass() { }
};

struct Derived1 : OtherClass, Base {
int t;
Derived1(int _x, int _z, int _t) : Base(_x), OtherClass(_z), t(_t) { }
virtual bar() {
std::cout << "Derived1::bar, x = " << x << ", z = " << z
<< ", t= " << t << endl; }
virtual foo() {
std::cout << "Derived1::foo, x = " << x << ", z = " << z
<< ", t= " << t << endl; }
virtual ~Derived1() { }
};

struct Derived2 : Base {
int y;
Derived2(int _x, int _y) : Base(_x), y(_y) { }
virtual foo() { std::cout << "Derived2::foo, x = " << x << ", y= " << y << endl; }
virtual ~Derived2() { }
};

main() {
Base *target = new Derived1(1,2,3);
Base *copyptr = target;
// Cast to Derived2
void *p = dynamic_cast<void *>(target);
target->~Base();
target = new (p) Derived2(4,5);
target->foo();
copyptr->foo();
delete target;
}
-- cut --

Result (with egcs 1.1b on Linux):
-- cut --
Derived2::foo, x = 4, y= 5
Base::foo, x= 5
-- cut --
Not good :-( Implementation is allowed to do such shift even with single
inheritance. Most will not do of course. Other reason why this non-portable
low-level hack is not usefull for portable programs :-))

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/