Topic: SizeOf Operator Overloadable?
Author: "Ronald F. Guilmette" <rfg@rahul.net>
Date: 6 Nov 1994 07:34:45 GMT Raw View
In article <783598181snz@wslint.demon.co.uk>,
Kevlin Henney <Kevlin@wslint.demon.co.uk> wrote:
>In article <rfgCy9tsM.27p@netcom.com>
> rfg@netcom.com "Ronald F. Guilmette" writes:
>
>>>You can't get a reference unless you have an lvalue. To get an lvalue
>>>requires evaluation.
>>
>>Ever heard of const references?
>
>Yes. Funnily enough, the fact that they are const makes no difference
>to the requirement for evaluation. Why would it?
But you were not speaking of evaluation. You were speaking of lvalues.
Const references _can_ be initialized with non-lvalues.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- E-mail: rfg@segfault.us.com ----------- Purveyors of Compiler Test ----
-------------------------------------------- Suites and Bullet-Proof Shoes -
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 24 Oct 1994 14:23:26 +0000 Raw View
In article <386cp9$197@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>
>[kevlin@wslint.demon.co.uk (Kevlin Henney) writes:]
>Kevlin> [...] further reflection has
>Kevlin> revealed no general purpose situation where knowing the dynamic size
>Kevlin> would actually be useful. I've thought about it, and I've asked others,
>Kevlin> but this does not seem to be useful outside of a number of toy
> programs.
>Kevlin> Any suggestions?
>
>It is usefull to access with a pointer of static type B*
>objects of a derived class D in an array.
I've outlined in a previous post why this is not practical. I have yet
to be convinced that it is useful [the absence of good examples is
telling ;-)]
>1. One idea of OO is: 'Any Derived instace IS also a Base instace'
> So you can always (dynamically) give a Derived
> where a Base was (statically) expected.
>2. The consequence:
> You can do anything with a object that (dynamically) is a Derived
> where a Bases was (statically) expected.
>3. It is just intuitive to also say (*):
> '10 Derived instances ARE also 10 Bases instances'
> So that you can always (dynamically) give 10 Deriveds
> where 10 Bases are (statically) expected.
> (*) The builtin mechanism of C++ to model 10 objects are arrays.
This seems to imply that to even everything up you would say that
Collection<Derived>
conforms to
Collection<Base>
It is left as an exercise for the reader to calculate the impact on
the language ;-)
>4. IMO the consequence is:
> You can do anything with 10 objects that (dynamically) are 10 Deriveds
> where 10 Bases were (statically) expected.
> (And this accessing one of the 10 objects by indexing!)
>
>When (4) is not OO then I am wrong. I always thought that it was
>just a problem of implementation that we could not do (4) in C++.
The standard OO model assumes reference semantics: C++ is based on C
which uses value semantics. So for reference semantics you are not
wrong, which is why arrays of pointers to polymorphic objects are
the preferred route.
[deleted]
>When operator sizeof were overloaded for the class of bp,
>then a call would be generated to evaluate sizeof dynamically
>at runtime.
>
>To me this is like replacing inline functions
>> inline size_t sizeof ( B &b ) { return 4; }
>> inline size_t sizeof ( D &d ) { return 8; }
But given that the expression that provides b must remain unevaluated,
how would this be achieved?
>by extern ones
>> extern size_t sizeof ( B &b );
>> extern size_t sizeof ( D &d );
>
>(Note that in this case sizeof is not a virtual method,
> so the argument does not have to be evaluated to do the call,
> only it's reference is taken)
You can't get a reference unless you have an lvalue. To get an lvalue
requires evaluation.
--
+---------------------------+-------------------------------------------+
| Kevlin A P Henney | Human vs Machine Intelligence: |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd | |
+---------------------------+-------------------------------------------+
Author: jjpersch@mac.shell.com (Jeff J. Persch)
Date: Tue, 25 Oct 1994 03:23:34 GMT Raw View
Try templates, which can do everything you want at *compile* time.
Don't expect a wart inherited from C (the builtin arrays with standard
conversion from array of T to pointer to T) to be OO ;)
Here's a quick array class based on the STL vector:
// allocate/deallocate
template <class T>
inline T* allocate(size_t size) {
return (T*)(::operator new(size * sizeof(T)));
}
template <class T>
inline void deallocate(T* pointer) {
::operator delete(pointer);
}
// construct/destroy
inline void* operator new(size_t, void* pointer) { return pointer; }
template <class T1, class T2>
inline void construct(T1* pointer, const T2& value) {
new (pointer) T1(value);
}
template <class T>
inline void destroy(T* pointer) {
pointer->~T();
}
// algorithms
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
while (first != last) { destroy(first++); }
}
template <class ForwardIterator, class Size, class T>
inline void uninitialized_fill_n(ForwardIterator first, Size n, const T& x) {
while (n--) construct(first++, x);
}
// array
template <class T>
class array {
protected:
T* start;
T* finish;
public:
array(size_t n, const T& value = T()) {
start = allocate<T>(n);
finish = start + n;
uninitialized_fill_n(start, n, value);
}
~array() {
destroy(start, finish);
deallocate(start);
}
T& operator[](size_t n) { return *(start+n); }
T const& operator[](size_t n) const { return *(start+n); }
};
Now when you mean array of T, just say array<T>.
Note that this also makes array new and array delete obsolete,
getting rid of a real source of programming errors.
For efficient and safe iteration, create an iterator class just like
STL's reverse_iterator: It wraps a T*, provides *, ++ (pre/post),
-- (pre/post), +, -, +=, -=, but is not implicitly converted to a T*.
For extra credit, rewrite this template so that sizeof(array<T>) ==
sizeof(T*) by encoding the length in the allocated storage.
You can have safe arrays without any extra run time or space costs.
Now how many other language features can be written in terms of
templates?
--
Jeffrey J. Persch
jjpersch@shell.com
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Wed, 26 Oct 1994 08:19:34 GMT Raw View
In article <783008606snz@wslint.demon.co.uk> Kevlin@wslint.demon.co.uk writes:
>
>I've outlined in a previous post why this is not practical. I have yet
>to be convinced that it is useful...
In other words, you've got your mind made up. Fine. I won't waste
time trying to change it.
>You can't get a reference unless you have an lvalue. To get an lvalue
>requires evaluation.
Ever heard of const references?
Maybe its time for you to catch up on your C++ reading a bit.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- E-mail: rfg@rahul.net ----------------- Purveyors of Compiler Test ----
-------------------------------------------- Suites and Bullet-Proof Shoes -
Author: c17m@alf.zfn.uni-bremen.de (Ralf Roth)
Date: 21 Oct 1994 13:30:43 GMT Raw View
Ulf Schuenemann (schuenem@Informatik.TU-Muenchen.DE) wrote:
: 1. One idea of OO is: 'Any Derived instace IS also a Base instace'
: So you can always (dynamically) give a Derived
: where a Base was (statically) expected.
[...]
: 3. It is just intuitive to also say (*):
: '10 Derived instances ARE also 10 Bases instances'
: So that you can always (dynamically) give 10 Deriveds
: where 10 Bases are (statically) expected.
agreed.
: (*) The builtin mechanism of C++ to model 10 objects are arrays.
The mechanism to give 10 objects is to have the function have
10 parameters.
It is true that Derived is-a Base, but it is not true that
array_of_Derived is-a array_of_Base. It was built by using
the array constructor with `Derived' -- it was not built using
inheritance from array_of_Base.
Perhaps it is a good idea to write one's own array classes
where DerivedArray is derived from BaseArray. The overhead of
this method should be comparable to that of a vitual sizeof-
operator. (Can anyone confirm this?)
----------------------------------------------------------------------
Ralf Roth c17m@zfn.uni-bremen.de
Author: c17m@alf.zfn.uni-bremen.de (Ralf Roth)
Date: 21 Oct 1994 12:47:23 GMT Raw View
Ronald F. Guilmette (rfg@netcom.com) wrote:
: struct B { int i; };
: struct D : public B { int j; } array[10];
: B *bp = array;
: void initialize_eyes ()
: {
: int i;
: for (i = 0; i < 10; i++)
: bp[i].i = 0;
: }
: This function will NOT produce the (apparently) desired/expected behavior.
The uuse of bp for indexing is illegal.
bp[i] is defined to be identical to *(bp+i). Addition is allowed only
for a pointer to an object IN AN ARRAY (ARM 5.7). bp is not of this
kind of pointer. It points to a B-object which is not in an array but
in a D-object.
The expected behavior (at least to me) is a runtime error.
In this simple case it could even be detected at compile time.
----------------------------------------------------------------------
Ralf Roth c17m@zfn.uni-bremen.de
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 27 Oct 1994 19:05:26 GMT Raw View
Topic: evaluation of the argument to sizeof.
There are three points where the size of a type/object is needed:
1. Explicit call
It's no problem to call "typeid(exp)->size()" instead of "sizeof exp".
This allows to distinguish between:
(A) dynamic size: runtime calculated size of a runtime EVALUATED expression
(B) static size: compiletime calculated size of an UNEVALUATED expression
2. Allocation (static, auto, dynamic)
[jjpersch@mac.shell.com (Jeff J. Persch) writes:]
> Stack allocation of objects? Sorry, can't know how much space to
> reserve until run-time. Your code runs slower.
> Would you like to have static objects? Sorry, don't know how much
> space to reserve in the bss until run-time. Guess they have to be
> heap allocated.
You can't call the sizeof-method because there is no object before
the creation. The compiler uses something like "sizeof T":
(C) type size: compiletime calculcated size of NO expr but of static type.
In the case of dynamic allocation the new/new[] operators can already
be overloaded to allocate as much as they want.
3. Pointer arithmetics
The idea is that pointer aritmetics only happen in the context of an
evaluated expression. Then the change from a compiletime constant to
runtime evaluation would not matter:
(D) dynamic/static size: run/compiletime calculated size of an EVALUATED expr
T *p = something;
(p+1)->foo(); // need to eval (p+1) for userdefined sizeof
bar(p+1); // and for calling foo() and bar() resp.
(p+1)->a = 1; // need to eval (p+1) for userdefined sizeof
// and for accessing member a
p = (p+1); // need to eval (p+1) for userdefined sizeof
// and for yielding a value to store to p
p++; // same as p=(p+1)
Did I miss a case where the expression does not need to be evaluated?
The question to solve is how to handle (A) to (D).
How about that:
ad (A) typeinfo has a size() method
ad (B) explicit sizeof (is the 'global' ::sizeof that) can not be overloaded
ad (C) no way to overload this, like (B)
ad (D) implicit sizeof can be overloaded only by userdefining operator sizeof
(operator sizeof can only be defined as a memberfunction)
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 27 Oct 1994 16:48:04 GMT Raw View
In article <783008606snz@wslint.demon.co.uk>, kevlin@wslint.demon.co.uk (Kevlin Henney) writes:
|> [..]
|> This seems to imply that to even everything up you would say that
|>
|> Collection<Derived>
|>
|> conforms to
|>
|> Collection<Base>
|>
|> It is left as an exercise for the reader to calculate the impact on
|> the language ;-)
Yes I would prefere this. Yes it would be a heavy impact. But it is
no problem that we don't have it, because it is consistant with the
typesystem.
Collection<Derived> deriveds;
Iterator<Derived> iderived (deriveds);
Iterator<Base> ibase1 (deriveds); // ERROR
Iterator<Base> ibase2 = iderived; // ERROR
On the other hand it is possible to write:
Derived deriveds[10];
Derived *iderived = deriveds;
Base *ibase1 = deriveds; // OK
Base *ibase2 = iderived; // OK
(++ibase1)->virtual_foo(); // runtime-error
(++ibase2)->virtual_foo(); // runtime-error
Yes, the problem pointer to single vs. pointer to array.
In C this is no problem because there is no inheritance that
allows without casting objects that are extended compared to
the expected object. In C++ we have this problem.
Do you agree that virtual sizeof would be one way to solve this
particular problem - regardless if this realy is a problem in your
opinion and regardless if you believe that it is worth it?
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 27 Oct 1994 18:13:10 GMT Raw View
In article <783008880snz@wslint.demon.co.uk>, kevlin@wslint.demon.co.uk (Kevlin Henney) writes:
|> In article <386ffa$1u4@hpsystem1.informatik.tu-muenchen.de>
|> schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
[..]
|> >In the case of && and || the second arguments to the builtin operators
|> >are not evaluated if the first argument determines the result,
|> >but they are always evaluated when userdefined!
|> >I can't remember anyone saying that this difference was a _big_ problem.
|>
|> The difference is that a virtual sizeof operator takes no argument:
|> its operand is the object that it is called on. Unless you have
|> evaluated that object, the sizeof operator cannot be called. Think of
|> it as the call:
|>
|> expr.operator sizeof()
I wanted to say that there already is a case in C++ where a builtin operator
that is nonstrict (does not always evaluate all its arguments) can be
userdefined by the cost of making it strict (evaluating all its arguments).
1st arg of && || 2nd arg | sizeof
-------------------------------------------------------------------
builtin always sometimes | never
userdefined always always | always
This is independent whether sizeof is userdefined as a method or as
a global function.
struct T {
size_t operator sizeof () { return 4; }
};
Or
size_t operator sizeof (const T&) { return 4; }
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 27 Oct 1994 17:32:56 GMT Raw View
In article <JJPERSCH.94Oct22164946@mac.shell.com>, jjpersch@mac.shell.com (Jeff J. Persch) writes:
|>
|> Why overload sizeof? What crippling problem needs this "solution"?
|>
|> Custom memory management?
|> No. You can already overload operator new. No big whoop.
|> If you need more space in your object, feel free to ignore or modify
|> the size_t argument to your new.
|>
|> [..]
Let's try an example: You want to implement a save delete that notices
when it is called on a new[]-ed array and not on a single object (and
vice-versa). You overload global new and new[] to place information
in front of every (place where an) object (will be constructed).
MemInfo: Memorymanagementinfo (8 bytes)
n: how many bytes in front of this object is the MemInfo (2 bytes)
ObjData: the plain object (4 bytes)
T *p = new; => [ MemInfo | 10 ObjData ]
^
|
p
T a[] = new[3]; => [ MemInfo | 10 ObjData | 16 ObjData | 22 ObjData ]
^ ^ ^
| | |
a a+1 a+2
Then for every pointer to a malloced T you can retrieve the MemInfo
and by that tell to what object it points to (single or n-th in array).
Problem: a+1 does not point to ObjData but to 16. Not even the constructors
of the a[i] (i>0) will be called with the wanted this-pointer.
Do you agree that virtual sizeof would be one way to solve this
particular problem - regardless if this realy is a problem in your
opinion and regardless if you believe that it is worth it?
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 31 Oct 1994 13:21:57 +0000 Raw View
In article <38oqjm$28f@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>I wanted to say that there already is a case in C++ where a builtin operator
>that is nonstrict (does not always evaluate all its arguments) can be
>userdefined by the cost of making it strict (evaluating all its arguments).
>
> 1st arg of && || 2nd arg | sizeof
>-------------------------------------------------------------------
>builtin always sometimes | never
>userdefined always always | always
>
>This is independent whether sizeof is userdefined as a method or as
>a global function.
Surely to be uniform, sizeof should always evaluate its 1st arg? :-)
>struct T {
> size_t operator sizeof () { return 4; }
>};
>Or
> size_t operator sizeof (const T&) { return 4; }
Other issues aside, if the sizeof operator is static then it can't be
virtual. If it is virtual, can I guarantee that
type obj;
assert(sizeof(type) == sizeof(obj));
will always succeed? If I can't, then what does it mean for these to be
different? The problem is that sizeof(obj) is not an operator on objects,
it is an operator on the static type of the object, ie. it is a convenience
notation for sizeof(type) that affords readability and maintainability.
Because it is not an operator on objects it cannot be made virtual. Another
proposal bites the dust...
As for whether you could make a case for a static overloadable sizeof
operator, well... ;-)
+---------------------------+-------------------------------------------+
| Kevlin A P Henney | Human vs Machine Intelligence: |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd | |
+---------------------------+-------------------------------------------+
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 31 Oct 1994 13:04:01 +0000 Raw View
In article <38oo88$1ko@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
> J. Persch) writes:
>|>
>|> Why overload sizeof? What crippling problem needs this "solution"?
>|>
>|> Custom memory management?
>|> No. You can already overload operator new. No big whoop.
>|> If you need more space in your object, feel free to ignore or modify
>|> the size_t argument to your new.
>|>
>|> [..]
>
>Let's try an example: You want to implement a save delete that notices
>when it is called on a new[]-ed array and not on a single object (and
>vice-versa). You overload global new and new[] to place information
>in front of every (place where an) object (will be constructed).
Overload delete[] if you overload new[].
>MemInfo: Memorymanagementinfo (8 bytes)
>n: how many bytes in front of this object is the MemInfo (2 bytes)
>ObjData: the plain object (4 bytes)
>
>T *p = new; => [ MemInfo | 10 ObjData ]
> ^
> |
> p
>
>T a[] = new[3]; => [ MemInfo | 10 ObjData | 16 ObjData | 22 ObjData ]
> ^ ^ ^
> | | |
> a a+1 a+2
>
>Then for every pointer to a malloced T you can retrieve the MemInfo
>and by that tell to what object it points to (single or n-th in array).
How will this work for builtin types? Putting a size_t in front of every
int will screw everything up. Since new and new[] are called w/ the actual
byte size required, as determined by the compiler, what happens in this case?
How will this work for user defined types? The compiler works out the
size by notionally using the other form of sizeof, ie. sizeof(type), which
I presume remains unaffected by all the baggage that the other form of
sizeof would acquire. In which case the size would be wrong and we'd be back
at square zero. If you make sizeof static, then it can't be virtual, which
is what you wanted in the first place.
>Problem: a+1 does not point to ObjData but to 16. Not even the constructors
>of the a[i] (i>0) will be called with the wanted this-pointer.
>
>Do you agree that virtual sizeof would be one way to solve this
>particular problem - regardless if this realy is a problem in your
>opinion and regardless if you believe that it is worth it?
Values aside, this example does not use a virtual sizeof and so it is not
a way to solve this problem. I believe the fact that this idea does not
work is probably the biggest argument against it ;-)
+---------------------------+-------------------------------------------+
| Kevlin A P Henney | Human vs Machine Intelligence: |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd | |
+---------------------------+-------------------------------------------+
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Tue, 1 Nov 1994 08:54:35 +0000 Raw View
In article <38olk4$sr@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>
>In article <783008606snz@wslint.demon.co.uk>, kevlin@wslint.demon.co.uk (Kevlin
> Henney) writes:
>|> [..]
>|> This seems to imply that to even everything up you would say that
>|>
>|> Collection<Derived>
>|>
>|> conforms to
>|>
>|> Collection<Base>
>|>
>|> It is left as an exercise for the reader to calculate the impact on
>|> the language ;-)
>
>Yes I would prefere this. Yes it would be a heavy impact. But it is
>no problem that we don't have it, because it is consistant with the
>typesystem.
It would actually break the type system. This relates to a point raised
in another thread about writing to such collections. Given that this is
the case for the generally accepted idea of collections, a virtual sizeof
(whatever that means) for C style arrays would have the opposite effect.
I would have thought that most people would have preferred to make it _more_
rather than _less_ collection-like.
+---------------------------+-------------------------------------------+
| Kevlin A P Henney | Human vs Machine Intelligence: |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd | |
+---------------------------+-------------------------------------------+
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 21 Oct 1994 20:31:51 GMT Raw View
In article <388fq3$7l3@gina.zfn.uni-bremen.de>, c17m@alf.zfn.uni-bremen.de (Ralf Roth) writes:
|> Ulf Schuenemann (schuenem@Informatik.TU-Muenchen.DE) wrote:
|> : 1. One idea of OO is: 'Any Derived instace IS also a Base instace'
|> : So you can always (dynamically) give a Derived
|> : where a Base was (statically) expected.
|> [...]
|> : 3. It is just intuitive to also say (*):
|> : '10 Derived instances ARE also 10 Bases instances'
|> : So that you can always (dynamically) give 10 Deriveds
|> : where 10 Bases are (statically) expected.
|> agreed.
|> : (*) The builtin mechanism of C++ to model 10 objects are arrays.
|> The mechanism to give 10 objects is to have the function have
|> 10 parameters.
|>
|> It is true that Derived is-a Base, but it is not true that
|> array_of_Derived is-a array_of_Base. It was built by using
|> the array constructor with `Derived' -- it was not built using
|> inheritance from array_of_Base.
Hhmm, this may be exactly the point where my idea of subtyping seems
to differ from C++. I believe that when Derived is a subtype of Base
then:
Derived[n] subtype of Base[n]
Set<Derived> subtype of Set<Base>
Derived f () subtype of Base f ()
I know that C++ is not a pure OOL. But I'm supporting every step in
this direction. The relaxation regarding returntype of overriding virtual
methods shows me that C++ is going the right path. ...
Now, where are the ones who started this discussion? rfg?
To me at least one sure point has emerged in the course of this
discussion:
It would be preferable to have a size() method in the typeinfo-class
I'm afraid it will be too late to get this into the standard.
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Sat, 22 Oct 1994 00:17:22 GMT Raw View
In article <3895t4$q6p@hpsystem1.informatik.tu-muenchen.de>,
Ulf Schuenemann <schuenem@Informatik.TU-Muenchen.DE> wrote:
>
>In article <CxzLGn.Eo5@borland.com>, pete@genghis.interbase.borland.com (Pete Becker) writes:
>|>
>|> The implication of this is that even when my D* actually points to
>|> an array of D's, the compiler must still generate code that goes through a
>|> virtual call for every operation that involves pointer arithmetic. This seems
>|> like a rather high price to pay in order to avoid having to write a class
>|> when this behavior is actually needed.
>
>When you do not userdefine operator sizeof than there is no change
>to the current situation. The idea is that you can overload sizeof when you
>need to treat an array of Deriveds like an array of Bases. Only then you have the
>overhead. And, yes, you have this overhead even if you dynamically have an array
>of the same type as the static type.
>(This is equal to nonvirtual vs. virtual methods where virtual
>methoddispatch is done even when the dynamic type is the same as
>the static type.)
No, it is not. If I have an object of type D and I call a function that
has been declared virtual the compiler can make a non-virtual call.
-- Pete
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 22 Oct 1994 08:50:42 GMT Raw View
In article <CxzLGn.Eo5@borland.com> pete@genghis.interbase.borland.com (Pete Becker) writes:
>
> The implication of this is that even when my D* actually points to
>an array of D's, the compiler must still generate code that goes through a
>virtual call for every operation that involves pointer arithmetic. This seems
>like a rather high price to pay in order to avoid having to write a class
>when this behavior is actually needed.
Yes Pete, but my suggestion was *only* that people be *allowed* to
declare their own virtual sizeof operators. In cases where no class-
specific sizeof operators actually *are* declared by the user, it is
my assumption that the normal (built-in) sizeof would be used instead
for pointer arithmetic calculations.
Thus, this is just another case of something which is free (except for the
cost of implementing it in the compiler) as long as you never use it.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 22 Oct 1994 08:57:58 GMT Raw View
In article <JASON.94Oct18165627@phydeaux.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>
>rfg often complains about how operator overloading is an abomination, so
>I'm surprised that he supports overloading sizeof, which IMO would lead to
>much more obfuscation...
I prefer a comprehensive and consistant abomination over an inconsistant
and incomplete abomination.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 22 Oct 1994 09:01:37 GMT Raw View
In article <388d8r$7l3@gina.zfn.uni-bremen.de> c17m@alf.zfn.uni-bremen.de (Ralf Roth) writes:
>Ronald F. Guilmette (rfg@netcom.com) wrote:
>: struct B { int i; };
>: struct D : public B { int j; } array[10];
>: B *bp = array;
>
>: void initialize_eyes ()
>: {
>: int i;
>
>: for (i = 0; i < 10; i++)
>: bp[i].i = 0;
>: }
>
>: This function will NOT produce the (apparently) desired/expected behavior.
>
>The uuse of bp for indexing is illegal.
>bp[i] is defined to be identical to *(bp+i). Addition is allowed only
>for a pointer to an object IN AN ARRAY (ARM 5.7). bp is not of this
>kind of pointer. It points to a B-object which is not in an array but
>in a D-object.
>
>The expected behavior (at least to me) is a runtime error.
Oh, you'll get a run-time error alright! :-) Finding such errors in
code written by someone else can however cause much tearing of hair
and gnashing of teeth.
>In this simple case it could even be detected at compile time.
Ten bucks says that you cannot name any existing commericial C++ compiler
which actually *will* detect it at compile time.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 22 Oct 1994 09:49:19 GMT Raw View
In article <37ssbk$jjb@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:
>rfg@netcom.com (Ronald F. Guilmette) writes:
>
>>In article <371m2k$qpf@engnews1.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
>>>
>>>If you want a dynamic sizeof operation, you can write one yourself for
>>>classes of interest; you just can't spell it "sizeof".
>
>>That is quite true, but that wouldn't have any effect upon certain
>>*implicit* invocations of `sizeof' which can occur in C and/or C++
>>code. Consider:
>
>> struct B { int i; };
>> struct D : public B { int j; } array[10];
>> B *bp = array;
>
>But you can't do this if you expect to step through the array.
>
>Arrays are not first-class data types in C++, a flaw inherited
>from C. Evidently, you assume the subtle implied conversions between
>arrays and pointers to be desirable.
No. I simply recognize and accept that such conversions do exist, and
that they are unlikely to go away.
>If you really want to make [pointers to arrays into]
>pointers to class objects, you should use an array
>class to contain them.
I have already said that I consider the creation of yet more (gratuitous)
types to be too ``heavy weight'' of a solution for this simple problem.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: jjpersch@mac.shell.com (Jeff J. Persch)
Date: Sat, 22 Oct 1994 21:49:45 GMT Raw View
Why overload sizeof? What crippling problem needs this "solution"?
Custom memory management?
No. You can already overload operator new. No big whoop.
If you need more space in your object, feel free to ignore or modify
the size_t argument to your new.
The conversion from 'array of T' to 'pointer to T'?
No. The standard template library provides a much cleaner solution
by using templated arrays. (and takes care of other array problems
at the same time without any runtime overhead)
> [I just can't remember the reasons against overloading sizeof. Maybe
> I've forgotten something important. Please tell me, when you know,
> so I can reconsider my thoughts.]
The implications of changing sizeof from a compile-time constant to a
run-time function are staggering.
Stack allocation of objects? Sorry, can't know how much space to
reserve until run-time. Your code runs slower.
Function returns an object? How much space should the caller
reserve? Sorry, don't know until run-time. Your code runs slower.
Array access? Simple pointer arithmetic? Again, your code runs
slower.
Would you like to have static objects? Sorry, don't know how much
space to reserve in the bss until run-time. Guess they have to be
heap allocated.
These are just a few of the things that sizeof affects.
Even if someone wanted to try and implement an overloaded sizeof, how
do you guarantee that that overloaded function always returns the same
value every time it is called? Not a simple task.
If the size of a type was allowed to vary per object,
then the offset of array[3] depends on sizeof array[2], sizeof
array[1], and sizeof array[0].
So not only is overloading sizeof a nightmare, the question still
remains: What problem does it solve???
--
Jeffrey J. Persch
jjpersch@shell.com
Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Thu, 20 Oct 1994 19:43:35 GMT Raw View
In article <386cp9$197@hpsystem1.informatik.tu-muenchen.de>,
Ulf Schuenemann <schuenem@Informatik.TU-Muenchen.DE> wrote:
>
>[kevlin@wslint.demon.co.uk (Kevlin Henney) writes:]
>Kevlin> [...] further reflection has
>Kevlin> revealed no general purpose situation where knowing the dynamic size
>Kevlin> would actually be useful. I've thought about it, and I've asked others,
>Kevlin> but this does not seem to be useful outside of a number of toy programs.
>Kevlin> Any suggestions?
>
>It is usefull to access with a pointer of static type B*
>objects of a derived class D in an array.
>
>1. One idea of OO is: 'Any Derived instace IS also a Base instace'
> So you can always (dynamically) give a Derived
> where a Base was (statically) expected.
>2. The consequence:
> You can do anything with a object that (dynamically) is a Derived
> where a Bases was (statically) expected.
>3. It is just intuitive to also say (*):
> '10 Derived instances ARE also 10 Bases instances'
> So that you can always (dynamically) give 10 Deriveds
> where 10 Bases are (statically) expected.
> (*) The builtin mechanism of C++ to model 10 objects are arrays.
>4. IMO the consequence is:
> You can do anything with 10 objects that (dynamically) are 10 Deriveds
> where 10 Bases were (statically) expected.
> (And this accessing one of the 10 objects by indexing!)
>
>When (4) is not OO then I am wrong. I always thought that it was
>just a problem of implementation that we could not do (4) in C++.
>
The implication of this is that even when my D* actually points to
an array of D's, the compiler must still generate code that goes through a
virtual call for every operation that involves pointer arithmetic. This seems
like a rather high price to pay in order to avoid having to write a class
when this behavior is actually needed.
-- Pete
Author: jjpersch@mac.shell.com (Jeff J. Persch)
Date: Thu, 20 Oct 1994 18:30:51 GMT Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
> Consider:
>
> struct B { int i; };
> struct D : public B { int j; } array[10];
> B *bp = array;
>
> void initialize_eyes ()
> {
> int i;
>
> for (i = 0; i < 10; i++)
> bp[i].i = 0;
> }
>
> [ deletion ]
>
> If the size used in the (implicit) multiplication were based upon the actual
> _dynamic_ sizes of the pointed-to elements (rather than upon their apparent
> static sizes) this code, and many other such examples, would produce the
> desired behavior rather than the kinds of mysterious bugs and crashes which
> now plague C++ programmers who inadvertantly write things like this.
>
> [ deletion ]
> how does one
> gain control over the *implicit* uses of sizeof which the compiler creates?
> Currently, there is no way to get such control in C++. This is a fundamental
> flaw in the language design IMHO.
The flaw is the conversion from array of type to pointer to type,
not the behavior of sizeof. Trying to 'cure' this basic premise of C
and C++ by changing the behavior of sizeof would have serious impact
on all code. I am not prepared to slow down my array accesses for
this fix. Imagine the extra confusion trying to explain this example
when it's outcome is dependent whether the class happenened to perform
some magical virtual sizeof declaration.
Want to cure the problem? Use a templated array class.
--
Jeffrey J. Persch
jjpersch@shell.com
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 24 Oct 1994 14:28:00 +0000 Raw View
In article <386ffa$1u4@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>> The one feature many people forget about the sizeof operator is that
>> it does not evaluate its operand. This is a _big_ problem for any
>> proposal that intends to do otherwise.
>
>In the case of && and || the second arguments to the builtin operators
>are not evaluated if the first argument determines the result,
>but they are always evaluated when userdefined!
>I can't remember anyone saying that this difference was a _big_ problem.
The difference is that a virtual sizeof operator takes no argument:
its operand is the object that it is called on. Unless you have
evaluated that object, the sizeof operator cannot be called. Think of
it as the call:
expr.operator sizeof()
If expr is unevaluated and sizeof is virtual, how do I call sizeof?
+---------------------------+-------------------------------------------+
| Kevlin A P Henney | Human vs Machine Intelligence: |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd | |
+---------------------------+-------------------------------------------+
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 18 Oct 1994 19:41:08 GMT Raw View
In article <rfgCxr2x3.Cyo@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
|> In article <371m2k$qpf@engnews1.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
|> >
|> >If you want a dynamic sizeof operation, you can write one yourself for
|> >classes of interest; you just can't spell it "sizeof".
|>
|> That is quite true, but that wouldn't have any effect upon certain
|> *implicit* invocations of `sizeof' which can occur in C and/or C++
|> code. Consider:
|> [example deleted]
|>
|> This function will NOT produce the (apparently) desired/expected behavior.
|> Why? Because of the fact that the indexing operation involves an implicit
|> multiplication of the index (`i') and the _static_ size of the type pointed
|> to by the `bp' pointer.
|> [...]
|> This example illustrates the _real_ reason why I believe that sizeof should
|> have been allowed to be a virtual member function.
|>
|> As Steve Clamage noted, programmers can easily write their own `size' member
|> functions, and they can even declare them to be virtual, but how does one
|> gain control over the *implicit* uses of sizeof which the compiler creates?
|> Currently, there is no way to get such control in C++. This is a fundamental
|> flaw in the language design IMHO.
I think until now the only way to control implicit operations of the compiler
is to substitute them by userdefined ones: defaultctor, copyctor, coercions.
IMHO it would be orthogonally that an (implicit) call to an overloaded
operator sizeof would generated at any place where sizeof is now implicitly
calculated at compiletime (using the static type).
[ And as a call is not a constant expression "int a[ sizeof B ];" is only
legal when class B has not an overloaded siezof ]
One could write:
struct B {
int i;
size_t operator sizeof() { return typeid(this).size(); }
};
This would solve the problem mentioned by Ronald.
Is it good to allow overloading of sizeof? - I'm not sure. I've read about
reasons to forbid it, but I can't remember.
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 18 Oct 1994 20:04:41 GMT Raw View
The implicit useages of sizeof I can think of are:
allocation(new/new[]), pointer-arithmetics (>indexing), delete[].
The more I think about overloading sizeof, the more I like it.
It would solve the static/dynamic-size problem that has some
annoying symptoms. Some thoughts:
- By overloading operator new/new[] you have control of where and
how much memory is allocated. You can allocate a bigger chunk than
the size of the plain object (to place additional information into it).
But indexing is calculated by the size of the plain object.
[I did not program an own memory-management, but to the ones who did:
Did you have any problems araising from this? Would overloaded
sizeof have helped you?]
When I can do my own memory-management, why may I not provide my
own sizeof to tell how big my obejct really is?
- More unexpected than indexing may be the implicit use of sizeof in
(builtin) delete[]:
Base *b10 = new Derived[10];
delete[] b10;
Using a virtual dtor does not help as the vtabel of the second
Derived is not at the place where the vtabel of b10[1] looked for.
- Arrays in C are a nice little thing with the least overhead possible.
But in C++ the dynamic type (and thus the size) can differ from the
static type. Static calcuated sizeof does not break the typesystem
(wrong type for an valid object -> use virtual) but even worse breaks
the integrity of an object (b10[1] is NOT A VALID OBJECT of any type,
but just a pice of memory). The problem is that now there is NO WAY to
influence pointer-arithmetics. Substituting the sizeof in this
calculations (not the + and *) would be the best way.
Being able to overload sizeof would be a easy-writable, easy-
understandable and orthogonal way to handle the problems mentioned.
[I just can't remember the reasons against overloading sizeof. Maybe
I've forgotten something important. Please tell me, when you know,
so I can reconsider my thoughts.]
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 18 Oct 1994 23:56:27 GMT Raw View
>>>>> Ulf Schuenemann <schuenem@Informatik.TU-Muenchen.DE> writes:
> [I just can't remember the reasons against overloading sizeof. Maybe
> I've forgotten something important. Please tell me, when you know,
> so I can reconsider my thoughts.]
I imagine they run somewhat along the lines of the reasons against
overloading '.', or operator void; implicit uses of sizeof are too
prevalent in the language, and allowing these implicit uses to be redefined
is too confusing. When you overload '+', at least you see a '+' whenever
your version is called.
rfg often complains about how operator overloading is an abomination, so
I'm surprised that he supports overloading sizeof, which IMO would lead to
much more obfuscation...
Jason
Author: jjpersch@mac.shell.com (Jeff J. Persch)
Date: Tue, 18 Oct 1994 00:39:50 GMT Raw View
kevlin@wslint.demon.co.uk (Kevlin Henney) writes:
> schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
> >I would prefere to extend the type_info class to include a
> >size()/dynamic_size() method, like:
> >
> >[jjpersch@mac.shell.com (Jeff J. Persch) writes:]
> >jeff> For a *virtual* sizeof operator, this is easily implemented
> >jeff> *if* the standard type_info class includes a size member:
> >jeff>
> >jeff> virtual_sizeof(x) -> typeid(x).size()
> >
> >Would this be a reasonable proposal? I think so:
> >- When name() is possible size() is no problem to implement,
> >- It requires just one size_t data per class,
> >- type_info is quite new, virtually now code would be broken.
> >
> >Any comments, pros, cons ?
>
> Seems like a good idea, except that it'd probably be worth skipping the
> virtual_sizeof operator altogether - the typeid and size expression is
> adequate (and in fact shorter by one char!). Since size is constant
> per object there is in principal no reason to even bother with a function.
It seems the original premise has gotten lost in the discussion.
Just to clarify, the original suggestion was that:
1) the sizeof operator should be made overloadable
2) the sizeof operator should be allowed to be virtual
We already know that (1) is very restricted since sizeof must evaluate
to a compile time constant, and therefore can only operate on static
type information. I can't think of any practical application for
overloading the sizeof of a type with another constant.
Prospect (2) runs counter to the definition of sizeof, since it is a
run-time operation. It should definitely not be called 'sizeof'.
In order achieve the effect of determining of size of a polymorphic
object at run time, I see two approaches:
a) boilerplate your classes with
'virtual size_t dynamic_size() const { return sizeof(*this); }'
b) use RTTI
Note that I was not suggesting that there should be an operator named
'virtual_sizeof', I was simply suggesting that the same effect could
be accomplished by using the already existing typeid() operator
combined with stored size information. Whether the size information
is stored in the type_info class, some subclass thereof, or even a
separate data structure indexed by typeid, is really not important.
Trying to push things in the type_info class is a dangerous road to
travel upon because that road has no end. Where do you draw the line
between standard (type_info) and optional (subclasses) information?
--
Jeffrey J. Persch
jjpersch@shell.com
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 17 Oct 1994 03:51:16 GMT Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <371m2k$qpf@engnews1.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
>>
>>If you want a dynamic sizeof operation, you can write one yourself for
>>classes of interest; you just can't spell it "sizeof".
>That is quite true, but that wouldn't have any effect upon certain
>*implicit* invocations of `sizeof' which can occur in C and/or C++
>code. Consider:
> struct B { int i; };
> struct D : public B { int j; } array[10];
> B *bp = array;
But you can't do this if you expect to step through the array.
Arrays are not first-class data types in C++, a flaw inherited
from C. Evidently, you assume the subtle implied conversions between
arrays and pointers to be desirable. IMHO they are undesirable and
cause no end of confusion. Unfortunately we are stuck with this model.
If you really want to deal with arrays of class objects, as opposed
to arrays of pointers to class objects, you should use an array
class to contain them. Then you can't make silly errors like
assigning an array of derived objects to a pointer-to-base.
--
Steve Clamage, stephen.clamage@eng.sun.com
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 17 Oct 1994 13:10:10 +0000 Raw View
In article <rfgCxr2x3.Cyo@netcom.com>
rfg@netcom.com "Ronald F. Guilmette" writes:
>Consider:
>
> struct B { int i; };
> struct D : public B { int j; } array[10];
> B *bp = array;
>
> void initialize_eyes ()
> {
> int i;
>
> for (i = 0; i < 10; i++)
> bp[i].i = 0;
> }
>
>This function will NOT produce the (apparently) desired/expected behavior.
>Why? Because of the fact that the indexing operation involves an implicit
>multiplication of the index (`i') and the _static_ size of the type pointed
>to by the `bp' pointer.
>
>If the size used in the (implicit) multiplication were based upon the actual
>_dynamic_ sizes of the pointed-to elements (rather than upon their apparent
>static sizes) this code, and many other such examples, would produce the
>desired behavior rather than the kinds of mysterious bugs and crashes which
>now plague C++ programmers who inadvertantly write things like this.
This is one of those nasty little areas of C++'s C inheritance (sic) that
is probably destined never to go away, and also the reason that the
standard requires (and the WP has) an array class.
The porblem w/ trying to use the dynamic size is illustrated by the following:
B *ep = array + 10;
ptrdiff_t len = ep - bp;
Pointer arithmetic would be nightmarish, and the above code would be
undefined: ep is well defined, but it may not be deref'd to access any
runtime size info.
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Thu, 20 Oct 1994 09:58:33 +0000 Raw View
In article <JJPERSCH.94Oct17193950@mac.shell.com>
jjpersch@shell.com "Jeff J. Persch" writes:
[deleted]
>In order achieve the effect of determining of size of a polymorphic
>object at run time, I see two approaches:
>
> a) boilerplate your classes with
> 'virtual size_t dynamic_size() const { return sizeof(*this); }'
> b) use RTTI
>
>Note that I was not suggesting that there should be an operator named
>'virtual_sizeof', I was simply suggesting that the same effect could
>be accomplished by using the already existing typeid() operator
>combined with stored size information. Whether the size information
>is stored in the type_info class, some subclass thereof, or even a
>separate data structure indexed by typeid, is really not important.
Yes, I quite liked this idea for dynamic size identification - noone
has yet been able to offer a consistent definition of what it means
to overload sizeof that wouldn't break the language. A library change
would be far easier to swallow.
>Trying to push things in the type_info class is a dangerous road to
>travel upon because that road has no end. Where do you draw the line
>between standard (type_info) and optional (subclasses) information?
However, I'm inclined to agree w/ you here: further reflection has
revealed no general purpose situation where knowing the dynamic size
would actually be useful. I've thought about it, and I've asked others,
but this does not seem to be useful outside of a number of toy programs.
Any suggestions?
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Thu, 20 Oct 1994 10:15:00 +0000 Raw View
In article <3819op$cs4@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>The implicit useages of sizeof I can think of are:
>allocation(new/new[]), pointer-arithmetics (>indexing), delete[].
>
>The more I think about overloading sizeof, the more I like it.
>It would solve the static/dynamic-size problem that has some
>annoying symptoms. Some thoughts:
>
>- By overloading operator new/new[] you have control of where and
> how much memory is allocated. You can allocate a bigger chunk than
> the size of the plain object (to place additional information into it).
> But indexing is calculated by the size of the plain object.
> [I did not program an own memory-management, but to the ones who did:
> Did you have any problems araising from this? Would overloaded
> sizeof have helped you?]
> When I can do my own memory-management, why may I not provide my
> own sizeof to tell how big my obejct really is?
Operators new and new[] are not virtual: they are class statics. I have
written my own memory management routines, but I cannot see how an
overloaded sizeof would help, I'm afraid.
>- More unexpected than indexing may be the implicit use of sizeof in
> (builtin) delete[]:
>
> Base *b10 = new Derived[10];
> delete[] b10;
>
> Using a virtual dtor does not help as the vtabel of the second
> Derived is not at the place where the vtabel of b10[1] looked for.
I can't think of a situation where code like this would be useful.
Any suggestions?
I would have said that this is an error in the same league as
Base *b10 = new Base[10];
delete b10;
>- Arrays in C are a nice little thing with the least overhead possible.
> But in C++ the dynamic type (and thus the size) can differ from the
> static type. Static calcuated sizeof does not break the typesystem
> (wrong type for an valid object -> use virtual) but even worse breaks
> the integrity of an object (b10[1] is NOT A VALID OBJECT of any type,
> but just a pice of memory). The problem is that now there is NO WAY to
> influence pointer-arithmetics. Substituting the sizeof in this
> calculations (not the + and *) would be the best way.
If a pointer is null, uninitialised or points one past the end of an array,
your program will explore the uncharted territories of undefined behaviour.
It also implies that the step for pacing through an 'array' would have
to be recalculated after each increment, given that it is easy to
contrive a situation where an array can hold two different kinds of objects:
char raw[sizeof(Base) + sizeof(Derived)];
new(raw) Base;
new(raw + sizeof(Base)) Derived;
Base *array = (Base *) raw;
>Being able to overload sizeof would be a easy-writable, easy-
>understandable and orthogonal way to handle the problems mentioned.
The one feature many people forget about the sizeof operator is that
it does not evaluate its operand. This is a _big_ problem for any
proposal that intends to do otherwise.
Thinking about the impact on pointer arithmetic, I'm reminded of the
proposal regarding invisible logic in OOLs ;-)
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 20 Oct 1994 18:26:49 GMT Raw View
[kevlin@wslint.demon.co.uk (Kevlin Henney) writes:]
Kevlin> [...] further reflection has
Kevlin> revealed no general purpose situation where knowing the dynamic size
Kevlin> would actually be useful. I've thought about it, and I've asked others,
Kevlin> but this does not seem to be useful outside of a number of toy programs.
Kevlin> Any suggestions?
It is usefull to access with a pointer of static type B*
objects of a derived class D in an array.
1. One idea of OO is: 'Any Derived instace IS also a Base instace'
So you can always (dynamically) give a Derived
where a Base was (statically) expected.
2. The consequence:
You can do anything with a object that (dynamically) is a Derived
where a Bases was (statically) expected.
3. It is just intuitive to also say (*):
'10 Derived instances ARE also 10 Bases instances'
So that you can always (dynamically) give 10 Deriveds
where 10 Bases are (statically) expected.
(*) The builtin mechanism of C++ to model 10 objects are arrays.
4. IMO the consequence is:
You can do anything with 10 objects that (dynamically) are 10 Deriveds
where 10 Bases were (statically) expected.
(And this accessing one of the 10 objects by indexing!)
When (4) is not OO then I am wrong. I always thought that it was
just a problem of implementation that we could not do (4) in C++.
[clamage@Eng.Sun.COM (Steve Clamage) writes:]
Steve> > struct B { int i; };
Steve> > struct D : public B { int j; } array[10];
Steve> > B *bp = array;
Steve>
Steve> But you can't do this if you expect to step through the array.
Yes, currently this (4) does not work. The implicit call of sizeof
to calculate the address of bp[1]: ((char*) bp) + sizeof *bp
is evaluated at compiletime using the static type of bp.
But I believe that (4) should work (for the sake of OO, intuitivity
and orthogonality) and one way to do so would be to supply a
matching overloaded sizeof:
When operator sizeof were overloaded for the class of bp,
then a call would be generated to evaluate sizeof dynamically
at runtime.
To me this is like replacing inline functions
> inline size_t sizeof ( B &b ) { return 4; }
> inline size_t sizeof ( D &d ) { return 8; }
by extern ones
> extern size_t sizeof ( B &b );
> extern size_t sizeof ( D &d );
(Note that in this case sizeof is not a virtual method,
so the argument does not have to be evaluated to do the call,
only it's reference is taken)
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 20 Oct 1994 19:12:42 GMT Raw View
Disclaimer: In my previous article #10969 I wrote:
(Note that in this case sizeof is not a virtual method,
so the argument does not have to be evaluated to do the call,
only it's reference is taken)
correct is of course:
(Note that in this case sizeof is not a virtual method,
so the argument does not have to evaluate to a legal object
to do the call, only it's reference is taken)
Sorry.
[kevlin@wslint.demon.co.uk (Kevlin Henney) writes:]
> > Base *b10 = new Derived[10];
> > delete[] b10;
> [..]
> I would have said that this is an error in the same league as
I thought that OO would mean that 10 Deriveds can be treated like 10
Bases. In C++ the builtin way to represent a number of objects is an
array. Resulting in: An array of 10 Deriveds can be treated like an
array of 10 Bases. In the same way like it goes for single Derived/Base.
> I would have said that this is an error in the same league as
>
> Base *b10 = new Base[10];
> delete b10;
On the other hand I think it does not violate the idea of OO to
distinguish an array (a set) of objects from a single object (element).
The problem of C++ in this case is that the typesystem does not
distinguish pointer to an array of objects from pointer to a single object.
But you may notice at runtime that there is a difference.
> It also implies that the step for pacing through an 'array' would have
> to be recalculated after each increment, given that it is easy to
> contrive a situation where an array can hold two different kinds of objects:
>
> char raw[sizeof(Base) + sizeof(Derived)];
> new(raw) Base;
> new(raw + sizeof(Base)) Derived;
> Base *array = (Base *) raw;
Of course, using placement-new and casting 'raw' memory you have to know what
you are doing. But this does not result in a worse behavior than now.
I would say in most cases arrays are created by new[n], giving you
an array of equalsized objects.
> The one feature many people forget about the sizeof operator is that
> it does not evaluate its operand. This is a _big_ problem for any
> proposal that intends to do otherwise.
In the case of && and || the second arguments to the builtin operators
are not evaluated if the first argument determines the result,
but they are always evaluated when userdefined!
I can't remember anyone saying that this difference was a _big_ problem.
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Tue, 18 Oct 1994 06:32:10 GMT Raw View
In article <JASON.94Oct16010011@phydeaux.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
>
>> As Steve Clamage noted, programmers can easily write their own `size' member
>> functions, and they can even declare them to be virtual, but how does one
>> gain control over the *implicit* uses of sizeof which the compiler creates?
>
>Smart pointers that call the size method.
Agreed, but smart-pointers seem to me to be an awfully ``heavy weight''
solution for such a modest problem.
I'd prefer to be able to solve this problem _without_ having to invent
new (and gratuitous) types.
(I could say the same thing about a _lot_ of problems in C++. Sadly, it
seems that the ``C++ solution'' to an awful lot of relatively simple
problems is to have the programmer create a new type. :-(
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: hopps@mmm.com (Kevin J Hopps)
Date: 17 Oct 1994 15:45:55 GMT Raw View
Ronald F. Guilmette (rfg@netcom.com) wrote:
> In article <371m2k$qpf@engnews1.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
> >
> >If you want a dynamic sizeof operation, you can write one yourself for
> >classes of interest; you just can't spell it "sizeof".
> That is quite true, but that wouldn't have any effect upon certain
> *implicit* invocations of `sizeof' which can occur in C and/or C++
> code. Consider:
> struct B { int i; };
> struct D : public B { int j; } array[10];
> B *bp = array;
> void initialize_eyes ()
> {
> int i;
> for (i = 0; i < 10; i++)
> bp[i].i = 0;
> }
> This function will NOT produce the (apparently) desired/expected behavior.
> Why? Because of the fact that the indexing operation involves an implicit
> multiplication of the index (`i') and the _static_ size of the type pointed
> to by the `bp' pointer.
> If the size used in the (implicit) multiplication were based upon the actual
> _dynamic_ sizes of the pointed-to elements (rather than upon their apparent
> static sizes) this code, and many other such examples, would produce the
> desired behavior rather than the kinds of mysterious bugs and crashes which
> now plague C++ programmers who inadvertantly write things like this.
> This example illustrates the _real_ reason why I believe that sizeof should
> have been allowed to be a virtual member function.
> As Steve Clamage noted, programmers can easily write their own `size' member
> functions, and they can even declare them to be virtual, but how does one
> gain control over the *implicit* uses of sizeof which the compiler creates?
> Currently, there is no way to get such control in C++. This is a
> fundamental
> flaw in the language design IMHO.
This is very interesting. Until now, none of your reasons have felt
compelling. My initial reaction to your example is that of course it
should not work. But it's possible my reaction comes from "what is"
rather than "what should be."
Even so, I'm not sure that this example should be made to work. My
reason does does not come from considering what else would break if
this were made to work.
Is it possible that what is wrong here is not that the code misbehaves (in
your opinion) but that C++ lets you use "pointer to" when "array of" is
what you mean? Perhaps my opinion is tainted by just having arrays work
this way for so long, but it seems wrong to make bp point to an array of
D and use it as if it were an array of B.
--
Kevin J. Hopps e-mail: kjhopps@mmm.com
3M Company phone: (612) 737-3300
3M Center, Bldg. 235-2D-45 fax: (612) 737-2700
St. Paul, MN 55144-1000 Opinions are my own. I don't speak for 3M.
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 21 Oct 1994 19:47:48 GMT Raw View
In article <CxzLGn.Eo5@borland.com>, pete@genghis.interbase.borland.com (Pete Becker) writes:
|>
|> The implication of this is that even when my D* actually points to
|> an array of D's, the compiler must still generate code that goes through a
|> virtual call for every operation that involves pointer arithmetic. This seems
|> like a rather high price to pay in order to avoid having to write a class
|> when this behavior is actually needed.
When you do not userdefine operator sizeof than there is no change
to the current situation. The idea is that you can overload sizeof when you
need to treat an array of Deriveds like an array of Bases. Only then you have the
overhead. And, yes, you have this overhead even if you dynamically have an array
of the same type as the static type.
(This is equal to nonvirtual vs. virtual methods where virtual
methoddispatch is done even when the dynamic type is the same as
the static type.)
When you put the logic into an Arrayclass you just transfere the overhead
to the implementation of this class.
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle9/~schuenem/index.html
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Tue, 11 Oct 1994 15:26:13 +0000 Raw View
In article <37bpro$dur@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>I would prefere to extend the type_info class to include a
>size()/dynamic_size() method, like:
>
>[jjpersch@mac.shell.com (Jeff J. Persch) writes:]
>jeff> For a *virtual* sizeof operator, this is easily implemented
>jeff> *if* the standard type_info class includes a size member:
>jeff>
>jeff> virtual_sizeof(x) -> typeid(x).size()
>
>Would this be a reasonable proposal? I think so:
>- When name() is possible size() is no problem to implement,
>- It requires just one size_t data per class,
>- type_info is quite new, virtually now code would be broken.
>
>Any comments, pros, cons ?
Seems like a good idea, except that it'd probably be worth skipping the
virtual_sizeof operator altogether - the typeid and size expression is
adequate (and in fact shorter by one char!). Since size is constant
per object there is in principal no reason to even bother with a function.
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 16 Oct 1994 05:22:14 GMT Raw View
In article <371m2k$qpf@engnews1.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
>
>If you want a dynamic sizeof operation, you can write one yourself for
>classes of interest; you just can't spell it "sizeof".
That is quite true, but that wouldn't have any effect upon certain
*implicit* invocations of `sizeof' which can occur in C and/or C++
code. Consider:
struct B { int i; };
struct D : public B { int j; } array[10];
B *bp = array;
void initialize_eyes ()
{
int i;
for (i = 0; i < 10; i++)
bp[i].i = 0;
}
This function will NOT produce the (apparently) desired/expected behavior.
Why? Because of the fact that the indexing operation involves an implicit
multiplication of the index (`i') and the _static_ size of the type pointed
to by the `bp' pointer.
If the size used in the (implicit) multiplication were based upon the actual
_dynamic_ sizes of the pointed-to elements (rather than upon their apparent
static sizes) this code, and many other such examples, would produce the
desired behavior rather than the kinds of mysterious bugs and crashes which
now plague C++ programmers who inadvertantly write things like this.
This example illustrates the _real_ reason why I believe that sizeof should
have been allowed to be a virtual member function.
As Steve Clamage noted, programmers can easily write their own `size' member
functions, and they can even declare them to be virtual, but how does one
gain control over the *implicit* uses of sizeof which the compiler creates?
Currently, there is no way to get such control in C++. This is a fundamental
flaw in the language design IMHO.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: jason@cygnus.com (Jason Merrill)
Date: Sun, 16 Oct 1994 08:00:11 GMT Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
> As Steve Clamage noted, programmers can easily write their own `size' member
> functions, and they can even declare them to be virtual, but how does one
> gain control over the *implicit* uses of sizeof which the compiler creates?
Smart pointers that call the size method.
Jason
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 6 Oct 1994 20:18:28 GMT Raw View
In article hpo@news.bridge.com, rodb@bridge.com (Rod Burman) writes:
>Surely the compiler could make sizeof(*base) return the correct size if a
>virtual table was present (sort of like RTTI restrictions),
What if 'base' is null? Ok, a special case: use the static size.
What if 'base' has not been initialized or points to a deleted object?
How do you tell at runtime? By luck, 'base' might contain something that
looks like the address of a valid object but isn't. Is it OK to get garbage
for an answer or a program abort? (Of course it isn't OK.)
Under current language rules, 'sizeof' never evaluates the subject expression,
so these questions do not arise. If you allow sizeof to be overloaded, the
overloaded versions would have to deal with these issues.
If you want a dynamic sizeof operation, you can write one yourself for
classes of interest; you just can't spell it "sizeof".
---
Steve Clamage, stephen.clamage@eng.sun.com
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Fri, 7 Oct 1994 08:16:07 +0000 Raw View
In article <rfgCx73Bt.BrL@netcom.com>
rfg@netcom.com "Ronald F. Guilmette" writes:
>In article <781200793snz@wslint.demon.co.uk> Kevlin@wslint.demon.co.uk writes:
>>In article <rfgCx177z.K8p@netcom.com>
>> rfg@netcom.com "Ronald F. Guilmette" writes:
>>>The fact of the matter is that sizeof should have been overloadable on
>>>a class-by-class basis, and it should have been possible to also declare
>>>it as virtual. Consider the following simple example:
>>>
>>> #include <stdio.h>
>>>
>>> struct B { int Bmbr; };
>>> struct D : public B { int Dmbr; };
>>>
>>> int main ()
>>> {
>>> B *bp = new D;
>>>
>>> printf ("size = %u\n", sizeof (*bp));
>>> return 0;
>>> }
>>>
>>>This code will yield the wrong answer. This problem (and many others
>>>which are directly or indirectly related to this one) could be solved
>>>easily if we were just allowed to add:
>>>
>>> virtual size_t operator sizeof () { return ::sizeof(*this); }
>>>
>>>to the definitions of both the B and D classes.
>>>
>>>(Note that some folks will argue that this sort of thing must not be
>>>allowed in the language because `sizeof' is a ``special'' kind of
>>>pervasive built-in operator which can be applied to any complete
>>>non-abstract type. But that argument is horse puckey. Consider
>>>that the unary & operator is an equally pervasive built-in operator,
>>>and yet the current language definition allows _that_ to be overloaded
>>>on a class-by-class basis.)
>>
>>Sorry Ron, but this is IMHO a lot of nonsense. Given your knowledge of
>>the language I'm surprised you'd entertain such ideas.
>
>Given your apparent _lack_ of knowledge, I'm surprized you felt qualified
>to put down a perfectly reasonable idea.
It is not reasonable, and I would suggest that you look at a few standard
refs [eg. a beginner's guide to C/C++ might help you, and I would suggest
following on with a book commonly known as K&R ;-) ] before exercising your
lack of knowledge in public.
>>Yes, sizeof
>>is an operator, and no it is not even remotely similar to the & operator.
>
>No similarity at all, eh? Did you perhaps forget that both may be applied
>to essentially any type of object?
Oh yes, sorry, and they're both in C and C++ and representable in
the ASCII character set. Yes they obviously have _loads_ in
common... ;-)
>>It is a compile time operation that does _not_ evaluate its operand.
>
>OK. So we say that it takes a reference type formal. What's the problem?
>
>>Your code fragment gives the correct answer.
>
>Some folks would disagree with that (narrow) view.
The value of a sizeof expresssion is determined at compile time and it
does not evaluate its operand. Perhaps you are having difficulty w/ these
basic concepts.
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: rodb@bridge.com (Rod Burman)
Date: 6 Oct 1994 19:35:36 GMT Raw View
Surely the compiler could make sizeof(*base) return the correct size if a
virtual table was present (sort of like RTTI restrictions), thus, for builtin
types and non-virtual classes sizeof(type) is (pseudo-implementation):
return const_size_of_type;
But for types with at least one virtual function it is:
return this->__vtabl->size_of_this_type;
assuming a call to a virtual function is implemented:
(this->__vtabl->function_table[FNC_OFFSET])
This would make sizeof() work like typeid() in the cases where RTTI was
available (alternatively may be we could call it RTTI_sizeof() or something)
This is NOT user overloading but it would produce more intuitive behaviour (to
some of us) at very little expense to compiler writers or standardisers, just
my 2 * <smallest local coin> worth.
RodB
#include <std_disclaimer>
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 10 Oct 1994 08:22:03 +0000 Raw View
In article <371ji8$hpo@news.bridge.com> rodb@bridge.com "Rod Burman" writes:
>Surely the compiler could make sizeof(*base) return the correct size if a
>virtual table was present (sort of like RTTI restrictions), thus, for builtin
>types and non-virtual classes sizeof(type) is (pseudo-implementation):
What if base is null or uninitialised? Also, given that the expression
for base cannot be evaluated anyway, how do you get to the vtable?
IMHO and IME, the standard solution for this problem is not to hack the
language but to write some code:
class SizeOf
{
public:
virtual size_t dynamic_size() const = 0;
}
...
size_t Derived::dynamic_size() const { return sizeof *this; }
I wouldn't get too hung up on the apparent similarities between
size and type - it's a red herring.
For a few cents more...
--
Kevlin A P Henney
kevlin@wslint.demon.co.uk
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 10 Oct 1994 16:24:24 GMT Raw View
sizeof evaluates at compiletime to the size of the static (compiletime-
determied) TYPE of an expression. A changed in this semantic would
be too drastic and leave us with the questionable "X *x=0; sizeof x;"
(Once I've not been convinced of that, but now I am)
But it would be nice to have a way to tell the size of the actual OBJECT
(dynamic size). One way would be:
[kevlin@wslint.demon.co.uk (Kevlin Henney) writes:]
kevlin> class SizeOf
kevlin> {
kevlin> public:
kevlin> virtual size_t dynamic_size() const = 0;
kevlin> }
kevlin> ...
kevlin> size_t Derived::dynamic_size() const { return sizeof *this; }
To work propperly I'd have to implement dynamic_size() (with only the
classname changing (*) ) in each derived class. This is clumpsy and
errorprone.
[ (*) Would be nice (but not neccessary) to have a kind of template
for this! "virtual member-templates"
class SizeOf {
{ public:
virtual template size_t dynamic_size() { return sizeof*this; }
}
I.e.: For each derived class (that does not override dynamic_size),
the template is instantiated, so the correct size of the *this is returned.
]
I would prefere to extend the type_info class to include a
size()/dynamic_size() method, like:
[jjpersch@mac.shell.com (Jeff J. Persch) writes:]
jeff> For a *virtual* sizeof operator, this is easily implemented
jeff> *if* the standard type_info class includes a size member:
jeff>
jeff> virtual_sizeof(x) -> typeid(x).size()
Would this be a reasonable proposal? I think so:
- When name() is possible size() is no problem to implement,
- It requires just one size_t data per class,
- type_info is quite new, virtually now code would be broken.
Any comments, pros, cons ?
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
Author: consp05@bingsuns.cc.binghamton.edu (SethMeister G.)
Date: 2 Oct 1994 02:58:03 GMT Raw View
Hi There,
I was just wondering why, in g++ and Borland C++ 4.0 one cannot
overload the sizeof operator. It IS an overator, isn't it? Am I
missing something?
-Seth
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 2 Oct 1994 05:57:35 GMT Raw View
In article <36l7jr$2b2@bingnet1.cc.binghamton.edu> consp05@bingsuns.cc.binghamton.edu (SethMeister G.) writes:
>Hi There,
>
> I was just wondering why, in g++ and Borland C++ 4.0 one cannot
>overload the sizeof operator. It IS an operator, isn't it?
Yes.
>Am I missing something?
If you are, so am I... and I have been for about 4+ years now.
The fact of the matter is that sizeof should have been overloadable on
a class-by-class basis, and it should have been possible to also declare
it as virtual. Consider the following simple example:
#include <stdio.h>
struct B { int Bmbr; };
struct D : public B { int Dmbr; };
int main ()
{
B *bp = new D;
printf ("size = %u\n", sizeof (*bp));
return 0;
}
This code will yield the wrong answer. This problem (and many others
which are directly or indirectly related to this one) could be solved
easily if we were just allowed to add:
virtual size_t operator sizeof () { return ::sizeof(*this); }
to the definitions of both the B and D classes.
(Note that some folks will argue that this sort of thing must not be
allowed in the language because `sizeof' is a ``special'' kind of
pervasive built-in operator which can be applied to any complete
non-abstract type. But that argument is horse puckey. Consider
that the unary & operator is an equally pervasive built-in operator,
and yet the current language definition allows _that_ to be overloaded
on a class-by-class basis.)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 3 Oct 1994 16:13:13 +0000 Raw View
In article <rfgCx177z.K8p@netcom.com>
rfg@netcom.com "Ronald F. Guilmette" writes:
>In article <36l7jr$2b2@bingnet1.cc.binghamton.edu>
> consp05@bingsuns.cc.binghamton.edu (SethMeister G.) writes:
>>Hi There,
>>
>> I was just wondering why, in g++ and Borland C++ 4.0 one cannot
>>overload the sizeof operator. It IS an operator, isn't it?
>
>Yes.
>
>>Am I missing something?
>
>If you are, so am I... and I have been for about 4+ years now.
>
>The fact of the matter is that sizeof should have been overloadable on
>a class-by-class basis, and it should have been possible to also declare
>it as virtual. Consider the following simple example:
>
> #include <stdio.h>
>
> struct B { int Bmbr; };
> struct D : public B { int Dmbr; };
>
> int main ()
> {
> B *bp = new D;
>
> printf ("size = %u\n", sizeof (*bp));
> return 0;
> }
>
>This code will yield the wrong answer. This problem (and many others
>which are directly or indirectly related to this one) could be solved
>easily if we were just allowed to add:
>
> virtual size_t operator sizeof () { return ::sizeof(*this); }
>
>to the definitions of both the B and D classes.
>
>(Note that some folks will argue that this sort of thing must not be
>allowed in the language because `sizeof' is a ``special'' kind of
>pervasive built-in operator which can be applied to any complete
>non-abstract type. But that argument is horse puckey. Consider
>that the unary & operator is an equally pervasive built-in operator,
>and yet the current language definition allows _that_ to be overloaded
>on a class-by-class basis.)
Sorry Ron, but this is IMHO a lot of nonsense. Given your knowledge of
the language I'm surprised you'd entertain such ideas. Yes, sizeof
is an operator, and no it is not even remotely similar to the & operator.
It is a compile time operation that does _not_ evaluate its operand. As
that is its definition, I cannot see how adding virtual behaviour would
be in anyway consistent - precognitive compilers perhaps? :-)
Your code fragment gives the correct answer. The following code will
also give the correct answer:
int main ()
{
B *bp = 0;
printf ("size = %u\n", sizeof (*bp));
return 0;
}
I would be very impressed if a virtual function could manage this.
--
Kevlin A P Henney
"I think therefore I am" is the statement of an
intellectual who severely underrates toothaches
Milan Kundera
Author: jjpersch@mac.shell.com (Jeff J. Persch)
Date: Wed, 5 Oct 1994 05:45:26 GMT Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
> The fact of the matter is that sizeof should have been overloadable on
> a class-by-class basis, and it should have been possible to also declare
> it as virtual. Consider the following simple example:
Why would you wan't to *overload* sizeof?
An *overloaded* sizeof would have to evalulate to a compile-time constant.
What can you do with that?
For a *virtual* sizeof operator, this is easily implemented
*if* the standard type_info class includes a size member:
virtual_sizeof(x) -> typeid(x).size()
--
Jeffrey J. Persch
jjpersch@shell.com
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Wed, 5 Oct 1994 10:19:05 GMT Raw View
In article <781200793snz@wslint.demon.co.uk> Kevlin@wslint.demon.co.uk writes:
>In article <rfgCx177z.K8p@netcom.com>
> rfg@netcom.com "Ronald F. Guilmette" writes:
>>The fact of the matter is that sizeof should have been overloadable on
>>a class-by-class basis, and it should have been possible to also declare
>>it as virtual. Consider the following simple example:
>>
>> #include <stdio.h>
>>
>> struct B { int Bmbr; };
>> struct D : public B { int Dmbr; };
>>
>> int main ()
>> {
>> B *bp = new D;
>>
>> printf ("size = %u\n", sizeof (*bp));
>> return 0;
>> }
>>
>>This code will yield the wrong answer. This problem (and many others
>>which are directly or indirectly related to this one) could be solved
>>easily if we were just allowed to add:
>>
>> virtual size_t operator sizeof () { return ::sizeof(*this); }
>>
>>to the definitions of both the B and D classes.
>>
>>(Note that some folks will argue that this sort of thing must not be
>>allowed in the language because `sizeof' is a ``special'' kind of
>>pervasive built-in operator which can be applied to any complete
>>non-abstract type. But that argument is horse puckey. Consider
>>that the unary & operator is an equally pervasive built-in operator,
>>and yet the current language definition allows _that_ to be overloaded
>>on a class-by-class basis.)
>
>Sorry Ron, but this is IMHO a lot of nonsense. Given your knowledge of
>the language I'm surprised you'd entertain such ideas.
Given your apparent _lack_ of knowledge, I'm surprized you felt qualified
to put down a perfectly reasonable idea.
>Yes, sizeof
>is an operator, and no it is not even remotely similar to the & operator.
No similarity at all, eh? Did you perhaps forget that both may be applied
to essentially any type of object?
>It is a compile time operation that does _not_ evaluate its operand.
OK. So we say that it takes a reference type formal. What's the problem?
>Your code fragment gives the correct answer.
Some folks would disagree with that (narrow) view.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -