Topic: Garbage Collection: State of ?
Author: michael.finney@acm.org (Michael Lee Finney)
Date: 1999/01/25 Raw View
In article <36A8A0FF.A26C16F7@i6.informatik.rwth-aachen.de>,
kais@i6.informatik.rwth-aachen.de says...
> mfinney@lynchburg.net wrote:
> > >What do you do with a struct you get from a library writtenin C? Do you propose
> > >to treat extern "C" structs differently from C++ PODS?
> >
> > This is a good question. I had not thought of that and it may
> > be a problem. I will have to think on it.
>
> How about modifying malloc() to add a dummy _vptr just before the mem it
> returns, with a destructor that does nothing ?
>
> To have a working GC would be really great !
That only works if I have control of the only C compiler on the system.
But, it is something to think about.
--
Michael Lee Finney
michael.finney@acm.org
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/01/25 Raw View
In article <36A901FA.2733F417@technologist.com>,
David R Tribble <dtribble@technologist.com> wrote:
>Scott Johnson wrote:
>> Are you arguing that it is a Bad Thing that the only (robust) error
>> handling mechanism for constructors is exceptions, as opposed to an
>> explicit return value?
>
>No, I'm arguing that constructors shouldn't cause errors in the
>first place.
Eh??? And just how, pray tell, are you going to guarentee that a
free-store allocation succeeds? Or that a file open succeeds?
The only way to ensure constructors cannot fail is to never do any
resource allocation of ANY sort in them. This forces a reversion to
the create and then initialize paradigm that constructors are
supposed to eliminate the need for.
>In which case the object is constructed, but in an "invalid" state,
>which we should be able to query (with another member function).
And just how are you going to make sure that ALL users always check the
state? What will you do if a user fails to check the state and then
uses the object? Are you going to force the overhead of an object
validity check on each access?
The general consensus is that a constructor should ALWAYS leave
an object in a usable state.
>Which is an argument against allowing constructors to fail in the
>first place.
>
>Due to the number of systems we port to, we are forced to code,
>for the time being, without exceptions. And in 600,000 lines of
>code, I can't think of one place where we needed a constructor
>to fail. Perhaps we're just lucky. It's more likely, though,
>that our design philosophy of lightweight constructors pays off in
>the long run, especially in maintenance costs.
How much has it cost you in extra error checks, and undetected uses
of incompletely initialized objects?
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/23 Raw View
David R Tribble wrote:
>
> David R Tribble wrote:
> > Yeah, same for constructors, which return errors only by throwing
> > exceptions. Dumb.
> >
> > So don't put anything in your constructors (or destructors) that
> > could cause errors. Only the other member functions should do that,
> > but they can also return error codes.
>
> Scott Johnson wrote:
> > Are you arguing that it is a Bad Thing that the only (robust) error
> > handling mechanism for constructors is exceptions, as opposed to an
> > explicit return value?
>
> No, I'm arguing that constructors shouldn't cause errors in the
> first place. The cleanup and signaling mechanisms involved are
> much more complicated that simply returning an error code. Thus
> the opportunity for doing the wrong thing is greater.
Why do you say that? I have no problems writing constructors that
clean up after themselves when they cannot initialize the object
fully.
> > If so, I can sympathize--exceptions being a
> > major performance hit, and not well-implemented on many compilers--but
> > I must ask how would one query the return value of a constructor?
> > Such would require an entirely new syntax for declaring objects.
> >
> > Exceptions in this case are better than the alternatives--setting
> > errno, or setting "valid bits" embedded in the object. I've written
> > class libraries on C++ compilers without exceptions available--and
> > properly handling valid bits is a major pain in the ass.
> In which case the object is constructed, but in an "invalid" state,
> which we should be able to query (with another member function).
And this is a maintenance headache.
Suppose we've got the following:
class base {
private:
bool valid_;
public:
base (void) {
// Do something that may fail
valid_ = /* init successful */;
}
vool isValid (void) const { return valid_; }
};
Using isValid_ works fine. But when someone else comes along and
does this....
class derived : public base {
public:
derived (void) {
// Do something that may fail
// Now what?
}
};
In this example, the derived class cannot alter the valid status
of the base class at all. Even if the base class designer remembers
to provide a protected setValid(bool) function...the derived class
designer still has to remember to explicitly CLEAR the valid flag
if it fails.
Trust me. If you get a complicated class hierarchy, especially one
where the writer of the derived class isn't the same person who
wrote the base, this can be a real headache.
> Or simply don't provide such complicated constructors to begin with;
> instead, use special conversion functions which can return/throw
> errors more cleanly and efficiently.
Such as? Throwing an exception out of a constructor is as clean as
any other function.
> > If you are suggesting that constructors ought not ever fail--THIS I
> > disagree with strongly. There are many valid reasons a constructor
> > might wish to fail--provided arguments are invalid; needed resources
> > are unavailable, etc, etc, etc. And failure of a constructor is a lot
> > harder to deal with than failure of a destructor.
> Which is an argument against allowing constructors to fail in the
> first place.
Excuse my above comment--I stated the exact opposite of what I meant
to say. I **MEANT** to say that failure of a constructor is a lot
EASIER to deal with than failure of a destructor.
You don't have to worry about double faults; constructors don't usually
get called in stack unwinding. In multithreaded implementations,
you usually don't have to worry about synchronization issues in the
constructor, assuming any functions you call are threadsafe, and you
don't do anything stupid.
> Due to the number of systems we port to, we are forced to code,
> for the time being, without exceptions. And in 600,000 lines of
> code, I can't think of one place where we needed a constructor
> to fail. Perhaps we're just lucky. It's more likely, though,
> that our design philosophy of lightweight constructors pays off in
> the long run, especially in maintenance costs. (This philosophy
> states that constructors merely initialize the members of the
> object and don't do any "heavy" operations like allocating other
> objects or calling functions that could fail.) And when we get to
> use exceptions (perhaps within two years), none of our code will
> need rewriting.
So, does each object then have an init() function, or something
similar? This technique does have advantages in some instances--usually
those when you need to do something that can happen only after the
object is fully constructed--spawning a thread, for instance. OTOH,
absent these instances, and ignoring the issue of exception portability,
dealing with initialization failure in the constructor is much cleaner.
After all--your object initializations can fail; you just deal with
this in a different place. And if exceptions aren't available,
your approach is quite reasonable--I've done the same myself in many
an instance.
Scott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/24 Raw View
In <787g3b$s7e@news3.euro.net>, "Martijn Lievaart" <nobody@orion.nl> writes:
>An intrusive GC could theoretically keep track of objects it just has
>deleted. So it could detect that an object now has a dangling pointer.
One of the suggestions that I made was that the vptr of a destructed
object be replaced by a special "dead" object vptr and so any further
attempt to reference the object via a virtual function, including the
destructor would potentially raise an exception so that the situation
you describe could be caught.
That doesn't work for PODs, but I was also suggesting that all GC
allocated objects have a vptr. It turns out that there may be some
problems with that, but I hope to find a solution (as soon as I have
a bit more time to look at the problem -- hopefully this weekend).
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Kai Sch tz" <kais@i6.informatik.rwth-aachen.de>
Date: 1999/01/24 Raw View
mfinney@lynchburg.net wrote:
> >What do you do with a struct you get from a library writtenin C? Do you propose
> >to treat extern "C" structs differently from C++ PODS?
>
> This is a good question. I had not thought of that and it may
> be a problem. I will have to think on it.
How about modifying malloc() to add a dummy _vptr just before the mem it
returns, with a destructor that does nothing ?
To have a working GC would be really great !
--
|/
|\ai
--------------------------------------------------------------------------------
Kai Schuetz
mailto:kais@i6.informatik.rwth-aachen.de
Hi, I'm not a signature virus. Why don't you just copy me into your
signature?
--------------------------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/24 Raw View
mfinney@lynchburg.net wrote:
>
> In <36A33E89.DF03D308@physik.tu-muenchen.de>, Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> >There's one problem: Arrays.
> >
> >For POD arrays, you must have the PODs without a gap, so you cannot
> >pau a vtbl pointer at the second, third, ... object of the array.
>
> Quite true. But my solution only places a vptr before the first object
> in the array, unless the array objects are virtual, in which case they
> (as now) each have a vptr. Since the garbage collector has to be
> able to find objects and arrays using interior pointers anyway, this
> restriction is not a problem.
But since it is only intended for the GC, why do you insist that
it is a vptr? I guess it would be more efficient if it were a
distinct pointer _directly_ to the finalizer routine (be it the
destructor, or any mother function; I don't like the idea of
destructors being called at random times; a distinct finalizer
should be provided in that case, IMHO). Or maybe more general to
a distinct "collection info block" which tells the collector
everything it must know about the type (f.ex. where the pointers
are).
If one creates the rule that memory allocated with malloc/raw
operator new will not be finalizes and scanned conservatively,
it could work:
new int[100]; // The compiler knows there are no pointers in there
new XY; // The compiler knows where the pointers are
operator new(100*sizeof(XY)); // The compiler doesn't know anything
malloc(1000); // nor does it here
Due to common usage, a new char[n] should be handled like
raw memory allocation.
Of course, the implementation might also analyse placement new,
find out if it is inside a block and adjust the collection info
accordingly; however, the extra cost for placement new might
bee too high for that.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/24 Raw View
In <36A9048F.34C79439@technologist.com>, David R Tribble <dtribble@technologist.com> writes:
No, I am using vptr because it is a pointer to a vtable. Even a POD
can have a vtable -- but it doesn't have much in there. The
destructor, of course, and any meta-data that the compiler
maintains in general or specifically for the garbage collector. The
trick is not allow the presence of the vptr for a POD to impact the
language implementation.
However, others have pointed out some problems with my approach
and I have to try to find some fixes to allow the scheme to be
compliant with the C++ standard with the minimum number of
restriction on the language or use of the language.
>mfinney@lynchburg.net wrote:
>>> 1. The vptr for all objects precede the object. This is
>>> not mandated by the C++ standard, but is allowed as I understand
>>> the standard
>
>Valentin Bonnard wrote:
>>> Your understanding isn't correct: a POD isn't allowed to
>>> have a vptr at the beginning.
>
>mfinney@lynchburg.net wrote:
>> You misunderstand. When you dynamically allocate a POD, you obtain a
>> pointer to a new instance. Almost all memory managers put anywhere
>> from 4 to 32 bytes of data before any dynamically allocated object or
>> array of objects. That data contains additional information the memory
>> manager needs to manage storage and also ensures that the object (or
>> the first object in the array) satisfies any alignment constraints.
>> There is sometimes additional data after the object which is used for
>> alignment between objects in an array. The data after the object must
>> be contained in the definition of sizeof(X) where X is an object (POD
>> or not). The data before the object is invisible to the programmer.
>>
>> If an extra pointer is placed before any such dynamically allocated
>> object, it does not affect the definition of the object itself (POD or
>> not) and the standard does not care about it. Therefore even POD's
>> can have a vptr -- but only for dynamically allocated POD's or POD's
>> which are not embedded in another object -- but only if the vptr
>> occurs before the object and not after it. Thus array accesses, etc.
>> all still work correctly. Because the vptr is not part of the
>> object.
>....
>
>You're using a confusing term, "vptr". What you describe is simply
>the memory manager's overhead for allocating a block (which exists
>if the block contains one object or an array of objects). A better
>term would be "blocksize" or "allocinfo", since "vptr" is too
>easily confused with "vtable" (which is sometimes called a "vptr").
>
>A "vtable" is a different thing, of course, and really only applies
>to objects having virtual functions. Every such object has a
>vtable, even if the object is a member of an array of objects.
>In contrast, a block containing an array of objects has a single
>allocinfo.
>
>-- David R. Tribble, dtribble@technologist.com --
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: michael.finney@acm.org (Michael Lee Finney)
Date: 1999/01/25 Raw View
In article <36A8AF37.63E3772@physik.tu-muenchen.de>, celtschk@physik.tu-
muenchen.de says...
> mfinney@lynchburg.net wrote:
> > In <36A33E89.DF03D308@physik.tu-muenchen.de>, Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> > >There's one problem: Arrays.
> > >For POD arrays, you must have the PODs without a gap, so you cannot
> > >pau a vtbl pointer at the second, third, ... object of the array.
> > Quite true. But my solution only places a vptr before the first object
> > in the array, unless the array objects are virtual, in which case they
> > (as now) each have a vptr. Since the garbage collector has to be
> > able to find objects and arrays using interior pointers anyway, this
> > restriction is not a problem.
> But since it is only intended for the GC, why do you insist that
> it is a vptr? I guess it would be more efficient if it were a
> distinct pointer _directly_ to the finalizer routine (be it the
> destructor, or any mother function; I don't like the idea of
> destructors being called at random times; a distinct finalizer
> should be provided in that case, IMHO). Or maybe more general to
> a distinct "collection info block" which tells the collector
> everything it must know about the type (f.ex. where the pointers
> are).
> If one creates the rule that memory allocated with malloc/raw
> operator new will not be finalizes and scanned conservatively,
> it could work:
> new int[100]; // The compiler knows there are no pointers in there
> new XY; // The compiler knows where the pointers are
> operator new(100*sizeof(XY)); // The compiler doesn't know anything
> malloc(1000); // nor does it here
> Due to common usage, a new char[n] should be handled like
> raw memory allocation.
> Of course, the implementation might also analyse placement new,
> find out if it is inside a block and adjust the collection info
> accordingly; however, the extra cost for placement new might
> bee too high for that.
As far as I can tell, not having examined the pathological cases too closely
yet, the problem exists no matter what I call the pointer. Since it is, to
me a vptr, that is what I call it. By associating the pointer with the
vtable, future possibilities are opened for language modifications. I am
considering language changes such as...
struct P {...a POD...};
struct V {...a class containing at least one virtual method...};
Then...
P x; // This does not have a vptr.
V y; // This does have a vptr.
which is the same as in the standard, but I could also allow...
virtual P r; // This does have a vptr.
void V s; // This does not have a vptr.
I could also allow the definitions...
virtual struct R {...a POD with a default vptr...};
void struct S {...a virtual object without a default vptr...};
but in both cases, the default could be overridden by explicitly requesting
or suppressing a vptr as in the example above.
You could also have...
P void * xp;
P virtual * rp;
V void * yp;
V virtual * sp;
and the following assignments could be made...
xp = rp;
yp = sp;
but the reverse assignments would not be legal without a cast...
rp = virtual_cast<P virtual *>(xp);
sp = virtual_cast<P virtual *>(yp);
And the idea is that "void" would be a "root" class of the system and that
every class directly or indirectly inherits from void. If a class has no
other base classes and does not explicitly mention void in its base class
list then the compiler can issue a warning for backward compatibility.
However, such an inheritance scheme does not impact anything because the
void class has no representation -- but it does make some virtual methods
available such as instanceSize() and a destructor (I would make all
destructors effectively virtual even where not declared, that has no impact
unless a vptr is present). This means that any object associated with a
vptr can reference those methods. Those methods would be available to the
garbage collector.
Then new would always return an object with a vptr, even if the type will be
case to a void object instead of a virtual object. Changes between void and
virtual pointers become trivial because the pointer itself does not change
and for a dynamically allocated POD, the vptr is part of the "virtual POD",
but not part of the "void POD". This means that a virtual POD could be
created (dynamically or otherwise) and still be passed to the operating
system or non-C++ programs without affecting anything else. The problem
with a vptr in the object is that you cannot convert a virtual object to a
POD without changing the pointer -- which is potentially dangerous.
The above approach also means that a virtual pointer to a base class can
still be dereferenced using operator[] because it is now possible to
determine the length of each element of the array. As it stands, C++ does
not have any polymorphic arrays, so that would be an interesting extension.
So, to me the pointer is a vptr which is rolled into the garbage collector
implementation, but it is much more. It is part of an attempt to make C++ a
more complete OO language. There are many other issues, but my goal is to
define a new language which is as compatible with standard C++ as possible,
but where necessary, some C compatibility can be lost. Just as C++ is an
upgrade from C, I would like the new language to be an upgrade from C++ in
the sense that almost all C++ programs remain legal.
I am willing to constrain the language in some ways, for example by not
allowing a pointer in a union. That doesn't make any more sense than
allowing a reference in a union -- especially if pointers and references are
all controlled by a non-conservative garbage collector.
Obviously, there are some problems remaining that need to be worked out, but
I believe that it is possible to do so. And parts of the approach I take
could be retrofitted into standard C++, such as for non-conservative garbage
collection.
--
Michael Lee Finney
michael.finney@acm.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/25 Raw View
mfinney@lynchburg.net wrote:
>
> In <36A9048F.34C79439@technologist.com>, David R Tribble <dtribble@technologist.com> writes:
>
> No, I am using vptr because it is a pointer to a vtable. Even a POD
> can have a vtable -- but it doesn't have much in there.
However, for a vtable to be at all useful, there must be a vptr embedded
in the object--or some OTHER mechanism for associating an object
with its vtable. Even if the standard were to allow a POD to ahve
a vptr; where would you put it? The only place that would make sense--
the very first entry, so the implementation would know where to find
it--would violate the requirement that a pointer to a POD and a pointer
to its first element point to the same storage.
> The
> destructor, of course, and any meta-data that the compiler
> maintains in general or specifically for the garbage collector. The
> trick is not allow the presence of the vptr for a POD to impact the
> language implementation.
About the only place I can think of that a vptr could go in a POD is
at the end. Given that, and a pointer or reference to a POD of
unknown length, how do you propose to find the vptr?
The following must work correctly:
struct POD_1 {
POD_1() : s(0) {}
short s;
};
class POD_2 {
POD_2() : d(0) {}
double d;
};
void *foo (bool cond) {
if (cond)
return new POD_1();
else
return new POD_2();
}
How would the vptr of the object returned by foo be found???
Scott
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/25 Raw View
Kai Sch=FCtz wrote:
>=20
> mfinney@lynchburg.net wrote:
> > >What do you do with a struct you get from a library writtenin C? Do =
you propose
> > >to treat extern "C" structs differently from C++ PODS?
> >
> > This is a good question. I had not thought of that and it may
> > be a problem. I will have to think on it.
>=20
> How about modifying malloc() to add a dummy _vptr just before the mem i=
t
> returns, with a destructor that does nothing ?
I don't believe that the standard specifies how malloc()/free() and/or
operator new()/delete() work; requiring these to attach metadata to=20
the returned storage strikes me as something which is venturing beyond
the scope of the standard.
Besides. At the point that malloc(), free(), operator new(), etc.
are called...the implementation typically does not know what sorta
object (if any) is being allocated. The memory allocation/deallocation
functions are only concerned with allocating storage--and aren't the
least bit concerned about what goes INTO that storage.=20
> To have a working GC would be really great !
To have one that works correctly and transparently for all conforming
C/C++ programs seems...problematic.
Would it be acceptable to consider garbage collection proposals that
are more limited in scope--for example, ones that require all GC'd
objects to have virtual functions or virtual base classes (no PODs),
or even to be derived from a common root class?
Will this be the straw that introduces class std::object into C++?
:)
Scott
=20
> --
> |/
> |\ai
>=20
> -----------------------------------------------------------------------=
---------
> Kai Schuetz
> mailto:kais@i6.informatik.rwth-aachen.de
> Hi, I'm not a signature virus. Why don't you just copy me into your
> signature?
> -----------------------------------------------------------------------=
---------
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with=
]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu =
]
> [ --- Please see the FAQ before posting. --- =
]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html =
]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/19 Raw View
In article <36A129B0.78C1@pratique.fr>,
Valentin Bonnard <bonnardv@pratique.fr> wrote:
> mfinney@lynchburg.net wrote:
>
> > 1. The vptr for all objects precede the object. This is
> > not mandated by the C++ standard, but is allowed as I understand
> > the standard
>
> Your understanding isn't correct: a POD isn't allowed to
> have a vptr at the beginning.
A POD isn't allowed to have a vptr, period.
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/20 Raw View
In <782hm9$b9r$1@nnrp1.dejanews.com>, James.Kanze@dresdner-bank.com writes:
>
>In article <36A129B0.78C1@pratique.fr>,
> Valentin Bonnard <bonnardv@pratique.fr> wrote:
>> mfinney@lynchburg.net wrote:
>>
>> > 1. The vptr for all objects precede the object. This is
>> > not mandated by the C++ standard, but is allowed as I understand
>> > the standard
>>
>> Your understanding isn't correct: a POD isn't allowed to
>> have a vptr at the beginning.
>
>A POD isn't allowed to have a vptr, period.
A POD can have a vptr if it really doesn't have a vptr. If the vptr
in question just "happens" to be before the POD and is part of
the memory management header for the dynamically allocated
POD, then the POD doesn'y really have a vptr as far as the
programmer is concerned. In practice, there just happens to be a
vptr where one would be expected under the scheme outlined
which could be useful in garbage collection. You could also put
a vptr before a POD which is statically allocated or allocated on
the stack, but which is not embedded in another object (a most
derived POD). Again, that vptr would be invisible to the programmer
but could be useful for the system by having an invariant that
all most derived objects (effectively) have a vptr. That is only
possible if the vptr is placed at -4 in the object layout so that it
is found the same place for a POD as for a virtual object where
the vptr is actually part of the virtual object unlike the case for
the POD.
I see this as an implementation "trick" that can be used to move
C++ a bit closer to a complete OO language without losing
compatability or costing anything in terms of memory mangement.
Michael Lee Finney
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/20 Raw View
In <36A33E89.DF03D308@physik.tu-muenchen.de>, Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
>There's one problem: Arrays.
>
>For POD arrays, you must have the PODs without a gap, so you cannot
>pau a vtbl pointer at the second, third, ... object of the array.
Quite true. But my solution only places a vptr before the first object
in the array, unless the array objects are virtual, in which case they
(as now) each have a vptr. Since the garbage collector has to be
able to find objects and arrays using interior pointers anyway, this
restriction is not a problem.
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/20 Raw View
In article <V_ho2.1627$TU6.3177557@newshog.newsread.com>,
mfinney@lynchburg.net wrote:
> On Sun, 17 Jan 1999 01:07:12 +0100, Valentin Bonnard wrote:
>
> >mfinney@lynchburg.net wrote:
> >
> >> 1. The vptr for all objects precede the object. This is
> >> not mandated by the C++ standard, but is allowed as I understand
> >> the standard
> >
> >Your understanding isn't correct: a POD isn't allowed to
> >have a vptr at the beginning.
>
> You misunderstand. When you dynamically allocate a POD, you obtain a p=
ointer
> to a new instance. Almost all memory managers put anywhere from 4 to 3=
2
> bytes of data before any dynamically allocated object or array of objec=
ts.
> That data contains additional information the memory manager needs to m=
anage
> storage and also ensures that the object (or the first object in the ar=
ray)
> satisfies any alignment constraints. There is sometimes additional dat=
a
> after the object which is used for alignment between objects in an arra=
y.
> The data after the object must be contained in the definition of sizeof=
(X)
> where X is an object (POD or not). The data before the object is invis=
ible
> to the programmer.
>
> If an extra pointer is placed before any such dynamically allocated obj=
ect,
> it does not affect the definition of the object itself (POD or not) and=
the
> standard does not care about it. Therefore even POD's can have a vptr =
-- but
> only for dynamically allocated POD's or POD's which are not embedded in
> another object -- but only if the vptr occurs before the object and not=
after
> it. Thus array accesses, etc. all still work correctly. Because the =
vptr
> is not part of the object.
Not quite, although the reasons aren't obvious. First, both the C and
the C++ standard require that results of casting a pointer to the first
element to void* and casting a pointer to the complete object to void*
compare equal. But the C standard also requires that casting a pointer
to the complete object to a void* result in a value which can be passed
to operator delete; since the user can supply the operator delete
function, no tricks are allowed there. The result is that in fact, the
pointer to the complete object, cast to void*, must actually point to
the first byte allocated for the object; there cannot be anything hidden
at that point. On the other hand, I don't think you could get away with
doing any fancy processing on the pointer to the first element, if that
element were, say an int (and of course, the pointer being cast could be
in a variable in another compilation unit).
The C++ standard also requires that the size passed to operator new be
the same as that returned by sizeof, so that placement new can be made
to work. (I.e. char* b =3D new operator new( sizeof T ) ; new ( b ) T ;)
It does occur to me that the compiler could systematically subtract 4
(or whatever) whenever it cast to void*, and add 4 when casting from
void*, but I still think that the sizeof constraint would prevent any
vptr. (I wonder. Could the compiler decide that inserting an extra
pointer after the first element is "appropriate padding"?)
--
James Kanze GABI Software, S=E0=
rl
Conseils en informatique orient=E9 objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------=3D=3D Posted via Deja News, The Discussion Network =3D=3D----=
------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own =
=20
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/20 Raw View
In <782i9m$bs2$1@nnrp1.dejanews.com>, James.Kanze@dresdner-bank.com writes:
>Not quite, although the reasons aren't obvious.
Good points all. Lets see if I answer them...
>First, both the C and
>the C++ standard require that results of casting a pointer to the first
>element to void* and casting a pointer to the complete object to void*
>compare equal.
I don't see a problem here. If a pointer to the complete object is
defined as the same as the zero offset in that object, the fact that
there is data at a negative offset does not change the pointer
value. If you have a POD...
struct POD {int a, int b};
and a pointer...
POD * x = new POD;
then as I have defined it, x is a pointer which points to the first
element of the new POD (a) and likewise, a pointer to the first
element is the same. The fact that there is an additional vptr
preceding the new POD is of relevance only to the garbage
collector (so far).
In fact, this requirement is not met by any compiler I am aware
of which places the vptr at offset 0 in a virtual object. For a
virtual object, a pointer to the first element and a pointer to
the complete object are not equal. They are using my scheme,
so my scheme satisfies a stronger invariant than C++ requires.
>But the C standard also requires that casting a pointer
>to the complete object to a void* result in a value which can be passed
>to operator delete; since the user can supply the operator delete
>function, no tricks are allowed there. The result is that in fact, the
>pointer to the complete object, cast to void*, must actually point to
>the first byte allocated for the object; there cannot be anything hidden
>at that point.
So far there isn't a problem. There is nothing hidden before the pointer
as far as anything but the garbage collector is concerned. And passing
such a void pointer to delete is exactly what you want to do. This is the
case whether we are talking about a POD or a virtual object.
>On the other hand, I don't think you could get away with
>doing any fancy processing on the pointer to the first element, if that
>element were, say an int (and of course, the pointer being cast could be
>in a variable in another compilation unit).
Since there is no fancy pointer adjustments required so far, this isn't
a problem.
>The C++ standard also requires that the size passed to operator new be
>the same as that returned by sizeof, so that placement new can be made
>to work. (I.e. char* b =3D new operator new( sizeof T ) ; new ( b ) T ;)
Since the length of an object is not changed using my scheme, including
for dynamically allocated PODs, this isn't a problem. Any user overriding
of operator new/delete does not need to allocate the extra vptr before a
POD -- that is suggested for a garbage collector cooperating with the
compiler. The total allocated size of a virtual object remains the same.
>It does occur to me that the compiler could systematically subtract 4
>(or whatever) whenever it cast to void*, and add 4 when casting from
>void*, but I still think that the sizeof constraint would prevent any
>vptr. (I wonder. Could the compiler decide that inserting an extra
>pointer after the first element is "appropriate padding"?)
That adjustment would not be necessary. There would be one automatic
adjustment required however. Whenever the compiler calls operator new
or operator delete for a virtual object, the pointer passed must be offset
by -4 from the pointer passed to the programmer for the allocated object.
This is not the case for PODs. This simply means that in the code...
class VOBJ {...};
VOBJ * x = new VOBJ;
the compiler will call operator new, it will when add +4 to the value which
it obtains and then it will call VOBJ::VOBJ() to construct the object. When
the code...
delete x;
is called, the compiler will call VOBJ::~VOBJ(), it will then add -4 to the
value of x and then it will call operator delete.
For a POD these additions would not be necessary. I had not thought of
these situations when I made my suggestions, but I can see that they
would have this one consequence. However, this is perfectly legal so
far as I can see. Everything the programmer is allowed to see is unchanged
and you even have some stronger invariants for virtual objects that you
did not have before.
The one place that I can see that there might be a problem is if the
programmer can directly call operator new() or operator delete() without
going through the language mechanism. I know that is possible for the
constructor/destructor (or is jus the destructor?), but other than to get or
release "raw" storage from another operator new or operator delete I
don't think that there is any direct access. And, of course, the pointer to
raw storage obtained in that manner would be just fine -- the adjustment
by +4/-4 would not occur in that context.
Perhaps I am not seeing everything, but I think that all bases are covered
here. But, I'm sure that someone will catch me if I am wrong! :-)
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Branko Cibej <branko.cibej@hermes.si>
Date: 1999/01/20 Raw View
mfinney@lynchburg.net wrote:
> [description of PODs with vptrs at offset -4]
> I see this as an implementation "trick" that can be used to move
> C++ a bit closer to a complete OO language without losing
> compatability or costing anything in terms of memory mangement.
What do you do with a struct you get from a library writtenin C? Do you propose
to treat extern "C" structs differently from C++ PODS?
--
Branko Cibej <branko.cibej@hermes.si>
HERMES SoftLab, Litijska 51, 1000 Ljubljana, Slovenia
phone: (++386 61) 186 53 49 fax: (++386 61) 186 52 70
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/20 Raw View
In article <iDhp2.3$If7.7461@newshog.newsread.com>,
mfinney@lynchburg.net wrote:
> In <782i9m$bs2$1@nnrp1.dejanews.com>, James.Kanze@dresdner-bank.com writes:
[...]
> There would be one automatic
> adjustment required however. Whenever the compiler calls operator new
> or operator delete for a virtual object, the pointer passed must be offset
> by -4 from the pointer passed to the programmer for the allocated object.
> This is not the case for PODs. This simply means that in the code...
>
> class VOBJ {...};
>
> VOBJ * x = new VOBJ;
>
> the compiler will call operator new, it will when add +4 to the value which
> it obtains and then it will call VOBJ::VOBJ() to construct the object. When
> the code...
>
> delete x;
>
> is called, the compiler will call VOBJ::~VOBJ(), it will then add -4 to the
> value of x and then it will call operator delete.
Consider the following:
void* p = ::operator new( sizeof( POD ) ) ;
POD* pp = new ( p ) POD ;
::operator delete( p ) ;
The standard requires this to work. It also requires the following to
work:
void* p = ::operator new( sizeof( POD ) ) ;
memcpy( p , &anOldPOD , sizeof( POD ) ) ;
POD* pp = (POD*)p ;
The compiler does not always know the actual type when calling the
operator new or delete functions. Which implies that the adjustment
will have to take place when the compiler does the type conversion, to
and from void. But then, the compiler doesn't know whether the object
was allocated on the heap or not, which will lead to a different set of
problems. And don't forget, the results of casting the address of the
object to void* and of casting the address of the first element to void*
must compare equal. The two conditions together imply that if the
compiler is going to adjust the pointer when casting to void*, it must
do it for *all* types, always.
> For a POD these additions would not be necessary. I had not thought of
> these situations when I made my suggestions, but I can see that they
> would have this one consequence. However, this is perfectly legal so
> far as I can see. Everything the programmer is allowed to see is unchanged
> and you even have some stronger invariants for virtual objects that you
> did not have before.
> The one place that I can see that there might be a problem is if the
> programmer can directly call operator new() or operator delete() without
> going through the language mechanism.
Precisely. It is actually a fairly frequent idiom in low level code:
all of my array classes do it in some way or another, as does my list
class and my associative array. The STL does it almost everywhere.
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: icedancer.zamboni@ibm.zamboni.net (Ken Walter)
Date: 1999/01/21 Raw View
On Wed, 20 Jan 1999 07:22:09, James.Kanze@dresdner-bank.com wrote:
The C++ standard also requires that the size passed to operator new be
the same as that returned by sizeof, so that placement new can be made
to work. (I.e. char* b new operator new( sizeof T ) ; new ( b ) T ;)
This kind of problem already occurs with placement new vectors.
In new(p) X[n], p must point to a buffer larger than sizeof(X[n])
or n*sizeof(X).
And there is no run-time/compile-time way of determining the overhead
which is implementation dependent.
Ken Walter
Remove .zamboni to reply
All the above is hearsay and the opinion of no one in particular
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/21 Raw View
In article <iDhp2.3$If7.7461@newshog.newsread.com>,
mfinney@lynchburg.net writes
>Perhaps I am not seeing everything, but I think that all bases are covered
>here. But, I'm sure that someone will catch me if I am wrong! :-)
I think you might reduce the level of confusion if you stopped calling
your device a vptr. Write up a proposal specifically to deal with a
pointer to precede everything else in dynamically allocated memory.
However, note that you will probably have to do something about
placement new, particularly where the programmer is using an arena into
which the dynamic objects are being placed.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/21 Raw View
In <XJryYeBHogp2Ewrn@robinton.demon.co.uk>, Francis Glassborow <francis@robinton.demon.co.uk> writes:
>I think you might reduce the level of confusion if you stopped calling
>your device a vptr. Write up a proposal specifically to deal with a
>pointer to precede everything else in dynamically allocated memory.
>However, note that you will probably have to do something about
>placement new, particularly where the programmer is using an arena into
>which the dynamic objects are being placed.
Others have already raised some serious issues that may
invalidate my idea -- at least until I can make sure that the
problems mentioned are covered.
However, I call it a vptr because it is explicitly a vptr. This was
actually taken out of context. My original idea was that all
objects would inherit directly or indirectly from the "void" object
and that any object, including one which was not explicitly
polymorphic could be declared "virtual". Further, any object
which has a vptr could be cast to a "virtual *" instead of a
"void *". Any "virtual *" could be cast to a "void *", but in doing
so the pointer would not change at all, but the preceding vptr,
if any, would no longer be referenced.
All of that should still be o.k.. However, I was also attempting
to overload use of the vptr for the garbage collector and in so
doing eliminate the extra memory overhead of always allocating
a vptr for dynamically allocated objects. This is where there may
be problems as others have pointed out. So, calling it a vptr is
still reasonable, but there are problems to be worked out.
My goal is to integrate non-conservative garbage collection into C++
in such a manner as to not cost the programmer anything when
garbage collection is not used while retaining maximal compatability
with standard C++. I would also like more meta information than
provide by standard C++ and a vptr is the most reasonable place
to put such hooks. So, always having a vptr available would be
very useful.
Michael Lee Finney
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/21 Raw View
In <7856u2$l76$1@nnrp1.dejanews.com>, James.Kanze@dresdner-bank.com writes:
>Consider the following:
>
> void* p = ::operator new( sizeof( POD ) ) ;
> POD* pp = new ( p ) POD ;
>
> ::operator delete( p ) ;
>
>The standard requires this to work. It also requires the following to
>work:
>
> void* p = ::operator new( sizeof( POD ) ) ;
> memcpy( p , &anOldPOD , sizeof( POD ) ) ;
> POD* pp = (POD*)p ;
>
>The compiler does not always know the actual type when calling the
>operator new or delete functions. Which implies that the adjustment
>will have to take place when the compiler does the type conversion, to
>and from void. But then, the compiler doesn't know whether the object
>was allocated on the heap or not, which will lead to a different set of
>problems. And don't forget, the results of casting the address of the
>object to void* and of casting the address of the first element to void*
>must compare equal. The two conditions together imply that if the
>compiler is going to adjust the pointer when casting to void*, it must
>do it for *all* types, always.
These are excellent points and counter-examples. I will definitely
have to think about this problem as well as the problem of obtaining
a POD from C library.
>> For a POD these additions would not be necessary. I had not thought of
>> these situations when I made my suggestions, but I can see that they
>> would have this one consequence. However, this is perfectly legal so
>> far as I can see. Everything the programmer is allowed to see is unchanged
>> and you even have some stronger invariants for virtual objects that you
>> did not have before.
>
>> The one place that I can see that there might be a problem is if the
>> programmer can directly call operator new() or operator delete() without
>> going through the language mechanism.
>
>Precisely. It is actually a fairly frequent idiom in low level code:
>all of my array classes do it in some way or another, as does my list
>class and my associative array. The STL does it almost everywhere.
This may well invalidate my idea -- or at least it means that I will
have to do some further work on the idea.
When (and if) I have a solution I'll repost -- a new thread if needed.
Michael Lee Finney
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Olivier Lefevre <olivier.lefevre@wdr.com>
Date: 1999/01/21 Raw View
--MimeMultipartBoundary
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
I believe this generalizes to any situation where two programs not
sharing the same address space exchange pointers, e.g., when calling
a C++ app. written in OO-style from another app. , which may even
be written in a different language. It's not a Windows or even GUI
issue.
-- O.L.
--MimeMultipartBoundary--
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/21 Raw View
In <36A5ED1A.C3DD0C2B@hermes.si>, Branko Cibej <branko.cibej@hermes.si> writes:
>What do you do with a struct you get from a library writtenin C? Do you propose
>to treat extern "C" structs differently from C++ PODS?
This is a good question. I had not thought of that and it may
be a problem. I will have to think on it.
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Martijn Lievaart" <nobody@orion.nl>
Date: 1999/01/21 Raw View
mfinney@lynchburg.net wrote in message ...
>
>In <77nocn$e3$1@uuneo.neosoft.com>, "Bill Wade" <bill.wade@stoner.com>
writes:
>
>>Suppose I have two dead objects, A and B. Each holds pointers to the
other
>>(they form a cycle, something that GC handles better than simple reference
>>counting).
>>
>>Now suppose the destructor for A contains
>> m_b->FooBar(); // A::m_b is the pointer to B
>>
>>How is GC supposed to know that it must destroy A before B?
>
>An excellent question with no perfect answer. However, there
>are several possible approaches.
>
>1. Require the programmer to be explicitly responsible for deleting
>cyclic objects with interdependencies such as above. In this case
>the GC will never see the objects, and if it does it can call the
>destructors in arbitrary order.
>
>2. Allow some pointers to be declared "weak". A weak pointer will
>not be followed for the purpose of collecting garbage. When the
>GC is finalizing, it can build a graph of dead objects using normal
>pointers only, and then finalize objects bottom up. Where a cycle
>remains, the GC would be allowed to finalize in an arbitary order.
>In the example above, object B will only contain weak pointers to
>object A.
>
>3. Allow every object to have a virtual method "bool isDead()" which
>is supplied by the system. The programmer could be required to not
>call methods on dead objects in their destructors.
>
>4. Require the compiler to perform additional analysis on destructors.
>If a destructor only deletes other objects and fiddles around internally,
>then it may be possible to automatically remove those destructors.
>Further, it may be possible to form a dependency graph on destructors
>using references (and possible weak pointers) to form an ordering to
>be imposed during finalization.
>
>5. Don't replace the vptr with the "dead" vptr until after all objects have
>been finalized. Then when A refers to B, it will still be there --
although
>this would sneak in some tolerance for dangling references, so it is most
>likely not a good idea.
>
>My recommendation: (2), possibly with some extra compiler analysis
>as in (4). The problem with the latter is that it depends too much
>on the quality of the compiler.
>
>
Some random thoughts:
1)
I think destructors and GC don't go together all to well. Do anything
non-trivial in your destructor and the above problem will become nearly
impossible to solve, as you indicated.
2)
I think the following will potentially break any GC, if used improperly t.i.
if the cyclic dependency is not broken before finalisation. the solutions
you give above will not work for this case I think. Only 4 could detect the
problem at compile time and alert the programmer to the potential dissaster.
(Btw, this code has exactly the same problem without GC, only probably being
easier to spot in testing).
// Pseusocode!
class B;
class A
{
A() : pB(0) {}
~A() { if (pB) pB->foo(); }
B *pB;
setB(B *newB) { pB = newB }
void bar();
};
class B
{
B() : pA(0) {}
~B() { if (pA) pA->bar(); }
A *pA;
setA(A *newA) { pA = newA }
void foo();
};
This code can be used correctly, so should we forbid it? How? I would
personally shoot the programmer who writes crap like this ;^>, but that is
besides the point. Point is that a GC should operate correctly on every
possible legal program, even if that program has a logical error.
An intrusive GC could theoretically keep track of objects it just has
deleted. So it could detect that an object now has a dangling pointer. If it
also knows that the pointer is used in the destructor it could assert the
user to the problem. This would also partially solve the original problem
above, but then *that* problem would be or wouldn't be detected, depending
on the fase of the moon, so it wouldn't be a panacea.
I would be very interested to see how existing GC's (not only for C++)
handle situations like this.
3)
I more and more get the feeling that cyclic dependencies are just not
solveable in a general way. You need programmer assistance for it, and I
actually don't think that is to bad. Weak pointers would go a long way to
solving most problems.
Just my E0,02
Martijn
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: rdamon@BeltronicsInspection.com (Richard Damon)
Date: 1999/01/22 Raw View
mfinney@lynchburg.net wrote:
>One caveat -- if the finializer is invoked through a vptr for a POD, then there
>could be a visible effect. This is a hit that I would be willing to take unless
>someone can come up with a compelling reason to allow slicing destructors.
>It seems to me that a slicing destructor is *always* a mistake, so that one
>visible effect would be to the programmer's advantage.
Evoking a "slicing destructor" is undefined behavior. If the destructor is not
virtual the deleting with a pointer to a base type is explicitly declared
undefined behavior.
--
richard_damon@iname.com (Redirector to my current best Mailbox)
rdamon@beltronicsInspection.com (Work Adddress)
Richad_Damon@msn.com (Just for Fun)
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/22 Raw View
David R Tribble wrote:
> Yeah, same for constructors, which return errors only by throwing
> exceptions. Dumb.
>
> So don't put anything in your constructors (or destructors) that
> could cause errors. Only the other member functions should do that,
> but they can also return error codes.
Scott Johnson wrote:
> Are you arguing that it is a Bad Thing that the only (robust) error
> handling mechanism for constructors is exceptions, as opposed to an
> explicit return value?
No, I'm arguing that constructors shouldn't cause errors in the
first place. The cleanup and signaling mechanisms involved are
much more complicated that simply returning an error code. Thus
the opportunity for doing the wrong thing is greater.
> If so, I can sympathize--exceptions being a
> major performance hit, and not well-implemented on many compilers--but
> I must ask how would one query the return value of a constructor?
> Such would require an entirely new syntax for declaring objects.
>
> Exceptions in this case are better than the alternatives--setting
> errno, or setting "valid bits" embedded in the object. I've written
> class libraries on C++ compilers without exceptions available--and
> properly handling valid bits is a major pain in the ass.
In which case the object is constructed, but in an "invalid" state,
which we should be able to query (with another member function).
Or simply don't provide such complicated constructors to begin with;
instead, use special conversion functions which can return/throw
errors more cleanly and efficiently.
> If you are suggesting that constructors ought not ever fail--THIS I
> disagree with strongly. There are many valid reasons a constructor
> might wish to fail--provided arguments are invalid; needed resources
> are unavailable, etc, etc, etc. And failure of a constructor is a lot
> harder to deal with than failure of a destructor.
Which is an argument against allowing constructors to fail in the
first place.
Due to the number of systems we port to, we are forced to code,
for the time being, without exceptions. And in 600,000 lines of
code, I can't think of one place where we needed a constructor
to fail. Perhaps we're just lucky. It's more likely, though,
that our design philosophy of lightweight constructors pays off in
the long run, especially in maintenance costs. (This philosophy
states that constructors merely initialize the members of the
object and don't do any "heavy" operations like allocating other
objects or calling functions that could fail.) And when we get to
use exceptions (perhaps within two years), none of our code will
need rewriting.
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/22 Raw View
mfinney@lynchburg.net wrote:
>> 1. The vptr for all objects precede the object. This is
>> not mandated by the C++ standard, but is allowed as I understand
>> the standard
Valentin Bonnard wrote:
>> Your understanding isn't correct: a POD isn't allowed to
>> have a vptr at the beginning.
mfinney@lynchburg.net wrote:
> You misunderstand. When you dynamically allocate a POD, you obtain a
> pointer to a new instance. Almost all memory managers put anywhere
> from 4 to 32 bytes of data before any dynamically allocated object or
> array of objects. That data contains additional information the memory
> manager needs to manage storage and also ensures that the object (or
> the first object in the array) satisfies any alignment constraints.
> There is sometimes additional data after the object which is used for
> alignment between objects in an array. The data after the object must
> be contained in the definition of sizeof(X) where X is an object (POD
> or not). The data before the object is invisible to the programmer.
>
> If an extra pointer is placed before any such dynamically allocated
> object, it does not affect the definition of the object itself (POD or
> not) and the standard does not care about it. Therefore even POD's
> can have a vptr -- but only for dynamically allocated POD's or POD's
> which are not embedded in another object -- but only if the vptr
> occurs before the object and not after it. Thus array accesses, etc.
> all still work correctly. Because the vptr is not part of the
> object.
...
You're using a confusing term, "vptr". What you describe is simply
the memory manager's overhead for allocating a block (which exists
if the block contains one object or an array of objects). A better
term would be "blocksize" or "allocinfo", since "vptr" is too
easily confused with "vtable" (which is sometimes called a "vptr").
A "vtable" is a different thing, of course, and really only applies
to objects having virtual functions. Every such object has a
vtable, even if the object is a member of an array of objects.
In contrast, a block containing an array of objects has a single
allocinfo.
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/18 Raw View
mfinney@lynchburg.net wrote:
>
> On Sun, 17 Jan 1999 01:07:12 +0100, Valentin Bonnard wrote:
>
> >mfinney@lynchburg.net wrote:
> >
> >> 1. The vptr for all objects precede the object. This is
> >> not mandated by the C++ standard, but is allowed as I understand
> >> the standard
> >
> >Your understanding isn't correct: a POD isn't allowed to
> >have a vptr at the beginning.
>
> You misunderstand. When you dynamically allocate a POD, you obtain a pointer
> to a new instance. Almost all memory managers put anywhere from 4 to 32
> bytes of data before any dynamically allocated object or array of objects.
> That data contains additional information the memory manager needs to manage
> storage and also ensures that the object (or the first object in the array)
> satisfies any alignment constraints. There is sometimes additional data
> after the object which is used for alignment between objects in an array.
> The data after the object must be contained in the definition of sizeof(X)
> where X is an object (POD or not). The data before the object is invisible
> to the programmer.
>
> If an extra pointer is placed before any such dynamically allocated object,
> it does not affect the definition of the object itself (POD or not) and the
> standard does not care about it. Therefore even POD's can have a vptr -- but
> only for dynamically allocated POD's or POD's which are not embedded in
> another object -- but only if the vptr occurs before the object and not after
> it. Thus array accesses, etc. all still work correctly. Because the vptr
> is not part of the object.
>
> For virtual objects, the vptr can be in the same location as for a POD, the
> offset is just -4 instead of 0 (on a 32-bit machine) and sizeof(X) must take
> the vptr into account. Thus every dynamically allocated object or array of
> ojects can have a vptr before the first object. That vptr can be used to
> replaced some or all of the information maintained by the memory manager.
>
> Therefore, every dynamically allocated object may have a vptr -- but only if
> the vptr occurs before the object and only if it only occurs once per
> dynamically allocated array for POD's.
>
> When you obtain such a dynamically allocated POD, the pointer is exactly the
> same as the pointer to a POD inside of another object as far as the data is
> concerned or anything else the programmer is allowed to "see".
There's one problem: Arrays.
For POD arrays, you must have the PODs without a gap, so you cannot
pau a vtbl pointer at the second, third, ... object of the array.
OTOH, for non-POD-arrays, you _must_ have the vptr (as part of the
object) separately for each object.
BTW, is there any reason why you want to get the vtbl into play?
Why not simply add a "finalizer pointer" at the beginning of
each dynamic memory block? Would also be more efficient (one less
indirection).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jens Kilian <Jens_Kilian@bbn.hp.com>
Date: 1999/01/18 Raw View
Pete Becker <petebecker@acm.org> writes:
> David R Tribble wrote:
> Easy: malloc allocates one extra object. Remember, the memory manager
> knows the details of the allocation scheme, so it can do things that
> user code is not allowed to do.
If the memory manager always puts a header on the blocks it returns,
it may not even be necessary to allocate the extra object:
...--+---+---+---+-+---+--...
| | | |H| |
...--+---+---+---+-+---+--...
^ ^
Last array element ----+ +---- Next allocated object
In this situation, GC could assume that a pointer to H (the header of the
next object) is the one-past-end pointer of the preceding array.
Jens.
--
mailto:jjk@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/18 Raw View
In article <V_ho2.1627$TU6.3177557@newshog.newsread.com>,
mfinney@lynchburg.net writes
>Therefore, every dynamically allocated object may have a vptr -- but only if
>the vptr occurs before the object and only if it only occurs once per
>dynamically allocated array for POD's.
And exactly how do you intend the my compiler to find that vptr when I
pass a reference to an element of an array to a function. Or are you
now proposing that references should carry the extra information about
the vptr?
What about managing aggrgates through pointers? Now every pointer must
include the location of the relevant vptr? What about a POD that
includes another POD as a member? etc.? etc.?
I do not think what you suggest is doable, and even if it were I doubt
that anyone would want to pay the performance costs.
>
>When you obtain such a dynamically allocated POD, the pointer is exactly the
>same as the pointer to a POD inside of another object as far as the data is
>concerned or anything else the programmer is allowed to "see".
>
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jerry Leichter <leichter@smarts.com>
Date: 1999/01/18 Raw View
| Reference counting may be inefficient to some extent, but it does
| allow for realtime performance characteristics....
So does garbage collection. Algorithms that allow this have been known
since the late '70's. (Yes, true real-time bounds: One can write down
the maximum number of instructions any call to the allocator or the
deallocator will execute, independent of the amount of free or allocated
memory - and that number can be fairly small.)
There's been a *huge* amount of work done on GC's. Unfortunately, the
world seems to be divided on almost religious grounds between those who
find GC impossible to live without, and those who are convinced it's
impractical for what they do. Members of the latter group usually
(certainly not *always*, but usually) haven't the foggiest idea of the
state of the art for garbage collection. They may have seen one des-
cription of how garbage collection was done in the original Lisp systems
in the early '60's, and believe that that's all there is to say about.
Or they've gotten their understanding of what GC costs from seeing the
"garbage collecting" message in earlier Emacs versions (which had a
really slow collector).
There's been a *lot* of study of the appropriateness of GC to a wide
variety of applications. The results are fairly clear: For almost all
applications, using GC rather than explicit memory allocation/dealloca-
tion costs essentially no extra time, but does cost you in memory usage.
Note that if you have memory leaks in the "explicit" system, in the long
run you'll use more space than the GC system anyway....
The exceptions in the above studies are typically programs that require
carefully hand-tuned memory management algorithms. A program that uses
the malloc/free or new/delete supplied with the system unchanged almost
not be of this type.
-- Jerry
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/19 Raw View
In <YBrD8ZAIHyo2EwiV@robinton.demon.co.uk>, Francis Glassborow <francis@robinton.demon.co.uk> writes:
>In article <V_ho2.1627$TU6.3177557@newshog.newsread.com>,
>mfinney@lynchburg.net writes
>>Therefore, every dynamically allocated object may have a vptr -- but only if
>>the vptr occurs before the object and only if it only occurs once per
>>dynamically allocated array for POD's.
>And exactly how do you intend the my compiler to find that vptr when I
>pass a reference to an element of an array to a function. Or are you
>now proposing that references should carry the extra information about
>the vptr?
>What about managing aggrgates through pointers? Now every pointer must
>include the location of the relevant vptr? What about a POD that
>includes another POD as a member? etc.? etc.?
>I do not think what you suggest is doable, and even if it were I doubt
>that anyone would want to pay the performance costs.
>>When you obtain such a dynamically allocated POD, the pointer is exactly the
>>same as the pointer to a POD inside of another object as far as the data is
>>concerned or anything else the programmer is allowed to "see".
You are seeing problems that don't exist. The idea is that virtual
objects already have vptrs. Dynamically allocated objects may or
may not have vptrs, but the memory manager always allocates a
header (under almost all memory management schemes). So the
idea is to replace that header (or part of that header) with the
vptr. So the memory used by dynamically allocated virtual objects
is less than it would have been, and for dynamically allocated PODs,
no more than it would have been.
The problems that you mention would exist with or without my
scheme. The programmer has a vptr available precisely under
the same circumstances that it is currently available. And under
most implementations, it is in the same relative location -- the
only difference is that the pointer is offset by +4, so virtual dispatch
code must be offset by -4. The programmer never sees the extra
vptr before a dynamically allocated POD or array of PODs. The
distance between two PODs in a dynamically allocated array of
PODs is unchanged.
The reason for making the vptr at -4 instead of 0 or some other
offset into the object is that it consolidates functionality that is
needed for both virtual objects and for the garbage collector. The
advantage of doing that, is that everything the garbage collector
needs -- the size of the object, the list of offsets of pointers/references
in the object and a pointer to finialization code can be maintained in the
vtable (perhaps the object size could be at 0 in the vtable and the offsets
of pointers/references at negative offsets -- so the vtable layout would
be same regardless of the inheritance heirarchy).
Because of the C++ language, the garbage allocator has to be able to find
the start of an object from an interior pointer and has to be able to find
the start of an array of objects from a pointer anywhere in the array. Given
that, it is not necessary to place a vptr before every POD in a dynamically
allocated array -- only in front of the first one. It also means that the use
a vptr before an object can actually make memory allocation more efficient
without impacting the language in any way visible to the programmer.
One caveat -- if the finializer is invoked through a vptr for a POD, then there
could be a visible effect. This is a hit that I would be willing to take unless
someone can come up with a compelling reason to allow slicing destructors.
It seems to me that a slicing destructor is *always* a mistake, so that one
visible effect would be to the programmer's advantage.
It also means that delete[] could release an array given a pointer to the
start of the array even when it does not know the actual type of the
array. It can look at -4 to get a pointer to the vtable and from there pick
up the size of the array and a pointer to finialization code to be run for
each object. Presumably -8 or some other scheme indicates the number
of elements in the array (already required by delete[]), so everything is
available that is needed for that language extension.
Michael Lee Finney
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/16 Raw View
In <77nocn$e3$1@uuneo.neosoft.com>, "Bill Wade" <bill.wade@stoner.com> writes:
>Suppose I have two dead objects, A and B. Each holds pointers to the other
>(they form a cycle, something that GC handles better than simple reference
>counting).
>
>Now suppose the destructor for A contains
> m_b->FooBar(); // A::m_b is the pointer to B
>
>How is GC supposed to know that it must destroy A before B?
An excellent question with no perfect answer. However, there
are several possible approaches.
1. Require the programmer to be explicitly responsible for deleting
cyclic objects with interdependencies such as above. In this case
the GC will never see the objects, and if it does it can call the
destructors in arbitrary order.
2. Allow some pointers to be declared "weak". A weak pointer will
not be followed for the purpose of collecting garbage. When the
GC is finalizing, it can build a graph of dead objects using normal
pointers only, and then finalize objects bottom up. Where a cycle
remains, the GC would be allowed to finalize in an arbitary order.
In the example above, object B will only contain weak pointers to
object A.
3. Allow every object to have a virtual method "bool isDead()" which
is supplied by the system. The programmer could be required to not
call methods on dead objects in their destructors.
4. Require the compiler to perform additional analysis on destructors.
If a destructor only deletes other objects and fiddles around internally,
then it may be possible to automatically remove those destructors.
Further, it may be possible to form a dependency graph on destructors
using references (and possible weak pointers) to form an ordering to
be imposed during finalization.
5. Don't replace the vptr with the "dead" vptr until after all objects have
been finalized. Then when A refers to B, it will still be there -- although
this would sneak in some tolerance for dangling references, so it is most
likely not a good idea.
My recommendation: (2), possibly with some extra compiler analysis
as in (4). The problem with the latter is that it depends too much
on the quality of the compiler.
Michael Lee Finney
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/16 Raw View
> David R Tribble wrote:
> >
> > Miniussi <miniussi@ilog.fr> wrote:
> > >> A real "problem" would be something like:
> > >>
> > >> char* p = malloc(100);
> > >> int offset = 42;
> > >> p -= offset;
> > >> [...]
> > >> p +=offset;
> > >>
> > >> since it's valid, does not use reinterpret_cast, and leave the
> > >> whole piece of memory unreferenced.
> >
> > James.Kanze@dresdner-bank.com wrote:
> > > It's not valid. If you write it, it is undefined behavior.
> >
> > Simple changes makes it conforming, though:
Pete Becker wrote:
> At the cost of no longer illustrating the problem that the original
> was intended to show, namely, using pointers that appear to point
> outside of objects. Pointers into the middle of an object are a
> completely different problem, one that's reasonably manageable.
Okay, I get the picture now.
So how about making p point to one-past-the-end of the array,
which is conforming, but which leaves p not pointing into the
original array object?
char* p = malloc(100);
int offset = 100;
p += offset; // p no longer points to malloc'd array.
... // malloc'd array has no pointers here.
p -=offset; // once again p points to malloc'd array.
free(p); // should not have been freed until now.
The problem, then, if I've finally understood it, is that we
have an allocated memory block with no pointers to it, but which
should not be garbage collected, because we eventually resurrect
a valid pointer to it. And we do it in a conforming way.
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/16 Raw View
Joe Keane wrote:
> Garbage collection is dumb.
So are memory leaks.
J. Kanze <kanze@gabi-soft.fr> wrote:
>> But that really doesn't solve the finalization problem. The real
>> "problem" is that finalization must sometimes take place at a fixed
>> moment. If I click on the close button on a window, I don't want the
>> window to hang around on the screen until garbage collection happens
>> to pick up the memory.
Then you've obviously designed your window managing code wrong; it
should close the window display and then release memory resources
(which can be GC'd later). A "close" button is supposed to trigger
an immediate action, right? Why rely on a delayed action (GC)?
> Well that's the thing about garbage collection, it tries to figure out
> when to free memory. It doesn't do so well, always freeing stuff
> late, but ignoring that, the main thing is, it does nothing for
> anything else.
Well, at least it frees the memory. Memory leaks don't.
> There are lots of things that are extremely similar: you open a file,
> you close it; you allocate memory, you free it; you map shared memory,
> you unmap it; you increment a counter, you decrement it.
>
> See a pattern here? Should i continue?
Yeah, yeah, and you allocate a block, you free a block, you allocate
a block, you allocate a block, you free a block, you allocate a
block, you allocate a block, you free a block, ...
See a pattern here?
Worse, you call a third-party library with memory leaks. See a
pattern here?
>> On the other hand, I find that using "delete p" to invoke
>> finalization, while a convenient shortcut, is often mixing two issue
>> that should be kept separate.
Perhaps your object should have a finalize() function that is separate
from, and does different things than, its destructor.
>> Suppose that for some reason, the
>> window cannot be closed: what happens if "delete p" is used?
Something a lot worse than when p->close() is called.
> You are right. C++ is dumb too.
>
> See the `exception from destructor' thread for more about this.
>
> IMHO, it's a fatal flaw that destruction has no provision for errors.
> That is a basic coding guideline, every function returns an error
> code.
Yeah, same for constructors, which return errors only by throwing
exceptions. Dumb.
So don't put anything in your constructors (or destructors) that
could cause errors. Only the other member functions should do that,
but they can also return error codes.
>> I've never believed in silver bullets. On the other hand, judging
>> from any number of postings in some of the Java groups, a lot of
>> other people do. (Worse, judging from the implementation of the
>> latest Java windowing interface, Swing, some of the Java implementers
>> do as well.)
>
> Java is dumb too.
>
> The good thing about all this stuff is that it doesn't work.
All programming languages are dumb. (Except for SNOBOL.)
> People get some urge to use all this new stuff and make something
> really nifty, and they work on it a lot, and it seems to work sort of,
> but it crashes now and then, and in truth it's really bloated and
> slow, and it has leaks that no one can figure out, and come to think
> of it, they spend much more time trying to make it work than anyone
> should.
>
> Meanwhile some of us program in C, and we call `malloc' and `free',
> and we're surely just Neanderthals for this, but we write stuff that
> people use every day and the stuff just works. And we tell these
> other people, yes you are very clever, much more than us, and please
> get back to us when routing and mail and Web service is done on your
> Lisp machines.
>
> Joe Keane, amateur
You've convinced me. I'm gonna to give up programming in C++,
forget all those suckers using my old C++ programs (which are
obviously inferior to my C programs), and go back to C.
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: iwelch@my-dejanews.com
Date: 1999/01/17 Raw View
Agreed. If there is no "newgc" operator in the program, garbage collection
need not be switched on...
/ivo welch
In article <76m05e$ert$1@remarQ.com>,
"Paul Sorensen" <psorensen@wedgewood.net> wrote:
>
> Was this something that was "switched on" by some directive - I don't think
> it's something that you'd want in all cases.
>
> Paul Sorensen
> Ivo Welch <ivo.welch@anderson.ucla.edu> wrote in message
> news:3680169B.8110DC67@anderson.ucla.edu...
> >
> >I read the dejanews archives of this group; a couple of years back there was
> >some discussion about the ANSI ISO committee looking into a GC scheme. What
> >happened to it? Is there hope? (A newgc operator would probably take half
> >the wind out of Java's sails, and make a lot of messy libraries a lot
> >nicer.)
> >
> >[Anyone know about gcc plans in this respect?]
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/01/17 Raw View
In article <369FDB19.D8C0C5CA@technologist.com>,
dtribble@technologist.com says...
[ ... ]
> The problem, then, if I've finally understood it, is that we
> have an allocated memory block with no pointers to it, but which
> should not be garbage collected, because we eventually resurrect
> a valid pointer to it. And we do it in a conforming way.
This is a well-enough defined situation that it's fairly easy for a
garbage collector to deal with it. The only hard part is for the GC
to figure out the size of object pointed to by the pointer so it knows
how far beyond the end of a block is still considered a pointer into a
block.
One safe and simple approach would involve assuming that each block is
only a single item so if a block extends from BASE to BASE+X bytes,
then any pointer between BASE and BASE+2X is treated as a pointer into
that block.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/17 Raw View
David R Tribble wrote:
>
>
> So how about making p point to one-past-the-end of the array,
> which is conforming, but which leaves p not pointing into the
> original array object?
Easy: malloc allocates one extra object. Remember, the memory manager
knows the details of the allocation scheme, so it can do things that
user code is not allowed to do.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/17 Raw View
David R Tribble wrote:
>
> Joe Keane wrote:
> > Garbage collection is dumb.
>
> So are memory leaks.
[snip]>
> >> On the other hand, I find that using "delete p" to invoke
> >> finalization, while a convenient shortcut, is often mixing two issue
> >> that should be kept separate.
>
> Perhaps your object should have a finalize() function that is separate
> from, and does different things than, its destructor.
Obviously.
Of course, one questions is--should the destructor call finalize()
if the object is garbage-collected without being finalized???
(Assuming that the "finalize()" method is responsible for informing
dependent objects, with a need to know, that the object is
going away; whereas the destructor is only responsible for deallocation
of privately-owned resources.)
> >> Suppose that for some reason, the
> >> window cannot be closed: what happens if "delete p" is used?
>
> Something a lot worse than when p->close() is called.
Precisely.
> > You are right. C++ is dumb too.
> >
> > See the `exception from destructor' thread for more about this.
> > IMHO, it's a fatal flaw that destruction has no provision for
> > errors. That is a basic coding guideline, every function returns an > > error code.
If we amend that to "every function that can fail in some way", and
extend "returning an error code" to other error-reporting mechanisms,
such as throwing exceptions or (God forbid) setting errno, and I'll
agree with you.
> Yeah, same for constructors, which return errors only by throwing
> exceptions. Dumb.
> So don't put anything in your constructors (or destructors) that
> could cause errors. Only the other member functions should do that,
> but they can also return error codes.
Are you arguing that it is a Bad Thing that the only (robust) error
handling mechanism for constructors is exceptions, as opposed to an
explicit return value? If so, I can sympathize--exceptions being a
major performance hit, and not well-implemented on many compilers--but
I must ask how would one query the return value of a constructor?
Such would require an entirely new syntax for declaring objects.
Exceptions in this case are better than the alternatives--setting errno,
or setting "valid bits" embedded in the object. I've written class
libraries on C++ compilers without exceptions available--and properly
handling valid bits is a major pain in the ass.
If you are suggesting that constructors ought not ever fail--THIS I
disagree with strongly. There are many valid reasons a constructor
might wish to fail--provided arguments are invalid; needed resources
are unavailable, etc, etc, etc. And failure of a constructor is a lot
harder to deal with than failure of a destructor.
[snip]
> > Java is dumb too.
> >
> > The good thing about all this stuff is that it doesn't work.
Java seems to work fine for me...of course, I know when to use it
and when not to use it.
> All programming languages are dumb. (Except for SNOBOL.)
Forth??? :)
> > People get some urge to use all this new stuff and make something
> > really nifty, and they work on it a lot, and it seems to work sort of,
> > but it crashes now and then, and in truth it's really bloated and
> > slow, and it has leaks that no one can figure out, and come to think
> > of it, they spend much more time trying to make it work than anyone
> > should.
> > Meanwhile some of us program in C, and we call `malloc' and `free',
> > and we're surely just Neanderthals for this, but we write stuff that
> > people use every day and the stuff just works. And we tell these
> > other people, yes you are very clever, much more than us, and please
> > get back to us when routing and mail and Web service is done on your
> > Lisp machines.
> > Joe Keane, amateur
> You've convinced me. I'm gonna to give up programming in C++,
> forget all those suckers using my old C++ programs (which are
> obviously inferior to my C programs), and go back to C.
How incredibly lazy, David. You should be programming in assembly
language--after all, yer compiler doesn't produce optimal code, you
know. :)
Scott
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/17 Raw View
mfinney@lynchburg.net wrote:
> 1. The vptr for all objects precede the object. This is
> not mandated by the C++ standard, but is allowed as I understand
> the standard
Your understanding isn't correct: a POD isn't allowed to
have a vptr at the beginning.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: William Boyle <woboyle@mediaone.net>
Date: 1999/01/18 Raw View
Reference counting may be inefficient to some extent, but it does allow
for realtime performance characteristics. As for the circular reference
problem, this is non-trivial. I am working on a solution to that, but it
is not complete as yet without programmer intervention. If you know that
a gc_ref contains a back-pointer, then it is possible to handle the
circular linkage - we do this now for a persistent object reference
manager used in our distributed transaction processing framework for
FACTORYworks, a large-scale manufacturing execution system. Since we
handle very high transaction volumes of very large object hierarchies
using this framework, obviously performance is not the main issue. Ad
hoc database queries and poorly written business rules cause most
performance problems with our system. FYI, FACTORYworks is currently
deployed world-wide to manage the biggest and highest volume
semiconductor plants. Chances are, most of the chips in your PC or
workstation were built at facilities using it. Theory is great, but
practice proves it.
William Boyle
Principal Software Engineer
Brooks Automation Software (formerly FASTech Integration, Inc.)
Scott Johnson wrote:
>
> Edward Luke wrote:
> >
> > AllanW@my-dejanews.com writes:
> >
> > > Essentially you've encapsulated a reference-counted pointer. The
> > > implementation of GC_ptr<T> would use a lower-level class which
> > > contains the T* and the reference count. When the reference
> > > count goes to 0, the lower-level class destroys the T and then
> > > destroys itself.
> >
> > Not quite. Reference counted pointers can't handle cyclic data
> > structures, they can handle DAG's as the day is long, but give them a
> > cycle and they're stuck. A true ,ummm... garbage collected pointer would
> > handle these cyclic cases. It is not clear to me that this can be
> > efficiently implemented without some compiler intervention.
>
> Reference counting is also rather inefficient in the presce of multi
> threading (or possibly even signal handlers.) Increasing or decreasing
> the reference count safely in either case requires, at minimum, an
> atomic read-modify-write cycle (or an architectures where this
> is not available, acquisition of a semaphore.)
>
> The latter is obviously an unacceptable amount of overhead; even
> the former can be cumbersome--especially on modern superscalar
> architectures where read-modify-writes throw a wrench into the pipeline.
>
> I think Sun has a paper somewhere on their website discussing reasons
> why reference counting was not used in Java; performance is just as
> much of an issue for them as the lack of proper handling of cyclical
> structures.
>
> With garbage collection, you just modify the pointers like you do
> today; the garbage collector worries about the rest.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/18 Raw View
On Sun, 17 Jan 1999 01:07:12 +0100, Valentin Bonnard wrote:
>mfinney@lynchburg.net wrote:
>
>> 1. The vptr for all objects precede the object. This is
>> not mandated by the C++ standard, but is allowed as I understand
>> the standard
>
>Your understanding isn't correct: a POD isn't allowed to
>have a vptr at the beginning.
You misunderstand. When you dynamically allocate a POD, you obtain a pointer
to a new instance. Almost all memory managers put anywhere from 4 to 32
bytes of data before any dynamically allocated object or array of objects.
That data contains additional information the memory manager needs to manage
storage and also ensures that the object (or the first object in the array)
satisfies any alignment constraints. There is sometimes additional data
after the object which is used for alignment between objects in an array.
The data after the object must be contained in the definition of sizeof(X)
where X is an object (POD or not). The data before the object is invisible
to the programmer.
If an extra pointer is placed before any such dynamically allocated object,
it does not affect the definition of the object itself (POD or not) and the
standard does not care about it. Therefore even POD's can have a vptr -- but
only for dynamically allocated POD's or POD's which are not embedded in
another object -- but only if the vptr occurs before the object and not after
it. Thus array accesses, etc. all still work correctly. Because the vptr
is not part of the object.
For virtual objects, the vptr can be in the same location as for a POD, the
offset is just -4 instead of 0 (on a 32-bit machine) and sizeof(X) must take
the vptr into account. Thus every dynamically allocated object or array of
ojects can have a vptr before the first object. That vptr can be used to
replaced some or all of the information maintained by the memory manager.
Therefore, every dynamically allocated object may have a vptr -- but only if
the vptr occurs before the object and only if it only occurs once per
dynamically allocated array for POD's.
When you obtain such a dynamically allocated POD, the pointer is exactly the
same as the pointer to a POD inside of another object as far as the data is
concerned or anything else the programmer is allowed to "see".
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/18 Raw View
In article <36A12954.17FB@nospam.aracnet.com>, Scott Johnson
<sj_nospam@nospam.aracnet.com> writes
>
>> Yeah, same for constructors, which return errors only by throwing
>> exceptions. Dumb.
>
>> So don't put anything in your constructors (or destructors) that
>> could cause errors. Only the other member functions should do that,
>> but they can also return error codes.
>
>Are you arguing that it is a Bad Thing that the only (robust) error
>handling mechanism for constructors is exceptions, as opposed to an
>explicit return value? If so, I can sympathize--exceptions being a
>major performance hit, and not well-implemented on many compilers--but
>I must ask how would one query the return value of a constructor?
>Such would require an entirely new syntax for declaring objects.
Oh, much worse! How are we going to cope with copy ctor's used to pass
arguments to parameters and return values from functions (including
overloaded operators)
>
>Exceptions in this case are better than the alternatives--setting errno,
>or setting "valid bits" embedded in the object. I've written class
>libraries on C++ compilers without exceptions available--and properly
>handling valid bits is a major pain in the ass.
>
>If you are suggesting that constructors ought not ever fail--THIS I
>disagree with strongly. There are many valid reasons a constructor
>might wish to fail--provided arguments are invalid; needed resources
>are unavailable, etc, etc, etc. And failure of a constructor is a lot
>harder to deal with than failure of a destructor.
>
>[snip]
>
>> > Java is dumb too.
>> >
>> > The good thing about all this stuff is that it doesn't work.
>
>Java seems to work fine for me...of course, I know when to use it
>and when not to use it.
And note that in Java all built-ins are passed by value and all UDT are
passed by address. If you wish to pass by value you must explicitly
create your own copy and handle the possible exceptions that might be
thrown by doing so.
>
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/14 Raw View
David R Tribble wrote:
>
> Miniussi <miniussi@ilog.fr> wrote:
> >> A real "problem" would be something like:
> >>
> >> char* p = malloc(100);
> >> int offset = 42;
> >> p -= offset;
> >> [...]
> >> p +=offset;
> >>
> >> since it's valid, does not use reinterpret_cast, and leave the whole
> >> piece of memory unreferenced.
>
> James.Kanze@dresdner-bank.com wrote:
> > It's not valid. If you write it, it is undefined behavior.
>
> Simple changes makes it conforming, though:
At the cost of no longer illustrating the problem that the original was
intended to show, namely, using pointers that appear to point outside of
objects. Pointers into the middle of an object are a completely
different problem, one that's reasonably manageable.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/14 Raw View
In article <Edhn2.310$TU6.703433@newshog.newsread.com>,
mfinney@lynchburg.net writes
>I have written many C/C++ programs where memory management
>was very complex. Garbage collection would certainly have helped
>in some of those programs. In one of them, which relied very
>heavily on heap-allocated objects, I found that the standard
>memory allocation routines were consuming some 80% of all cpu
>resources for the program. Even a poor garbage collector would
>probably not consume more than 10%.
No, I think that the GC would probably consume about the same time, or a
bit more. But that is beside the point, it is your time that would be
saved together with eliminating the potential for bugs caused by your
loosinn track and destroying objects early.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/14 Raw View
Edward Luke wrote:
>
> AllanW@my-dejanews.com writes:
>
> > Essentially you've encapsulated a reference-counted pointer. The
> > implementation of GC_ptr<T> would use a lower-level class which
> > contains the T* and the reference count. When the reference
> > count goes to 0, the lower-level class destroys the T and then
> > destroys itself.
>
> Not quite. Reference counted pointers can't handle cyclic data
> structures, they can handle DAG's as the day is long, but give them a
> cycle and they're stuck. A true ,ummm... garbage collected pointer would
> handle these cyclic cases. It is not clear to me that this can be
> efficiently implemented without some compiler intervention.
Reference counting is also rather inefficient in the presce of multi
threading (or possibly even signal handlers.) Increasing or decreasing
the reference count safely in either case requires, at minimum, an
atomic read-modify-write cycle (or an architectures where this
is not available, acquisition of a semaphore.)
The latter is obviously an unacceptable amount of overhead; even
the former can be cumbersome--especially on modern superscalar
architectures where read-modify-writes throw a wrench into the pipeline.
I think Sun has a paper somewhere on their website discussing reasons
why reference counting was not used in Java; performance is just as
much of an issue for them as the lack of proper handling of cyclical
structures.
With garbage collection, you just modify the pointers like you do
today; the garbage collector worries about the rest.
Scott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/14 Raw View
Francis Glassborow wrote:
>
>
> No, I think that the GC would probably consume about the same time, or a
> bit more. But that is beside the point, it is your time that would be
> saved together with eliminating the potential for bugs caused by your
> loosinn track and destroying objects early.
Offset in part by the time that is lost tracking down non-memory
resource leaks resulting from the absence of reliable destruction of
objects. <g>
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/01/15 Raw View
mfinney@lynchburg.net wrote in message
<9uhn2.311$TU6.703433@newshog.newsread.com>...
>
>I think that that finialization problem is reasonably trivial. It
>can be handled in the following manner...
>
> [deleted lots of details for 4.]
>
>4. When the garbage collector runs, it always calls the
>destructor for that object
Suppose I have two dead objects, A and B. Each holds pointers to the other
(they form a cycle, something that GC handles better than simple reference
counting).
Now suppose the destructor for A contains
m_b->FooBar(); // A::m_b is the pointer to B
How is GC supposed to know that it must destroy A before B?
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/13 Raw View
In article <77f484$est$1@rocky.jgk.org>, Joe Keane <jgk@jgk.org> writes
>Meanwhile some of us program in C, and we call `malloc' and `free', and
>we're surely just Neanderthals for this, but we write stuff that people
>use every day and the stuff just works. And we tell these other people,
>yes you are very clever, much more than us, and please get back to us
>when routing and mail and Web service is done on your Lisp machines.
I first came across the principles of conservative garbage collection in
C. Some type of application work well with GC (conservative or
otherwise) and some do not. Java does not give us any choice, C++ does
though the choice could be improved. How to change the standard to
provide better support for doing that is a suitable subject for this NG.
I do not think the tone of your posting is quite appropriate.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Edward Luke <lush@erc.msstate.edu>
Date: 1999/01/13 Raw View
AllanW@my-dejanews.com writes:
> Essentially you've encapsulated a reference-counted pointer. The
> implementation of GC_ptr<T> would use a lower-level class which
> contains the T* and the reference count. When the reference
> count goes to 0, the lower-level class destroys the T and then
> destroys itself.
Not quite. Reference counted pointers can't handle cyclic data
structures, they can handle DAG's as the day is long, but give them a
cycle and they're stuck. A true ,ummm... garbage collected pointer would
handle these cyclic cases. It is not clear to me that this can be
efficiently implemented without some compiler intervention.
IMO, C++ main lacking point is a means of dealing with this problem in
a standard fashion. After all, memory allocation is one of the
remaining sticky wicket that mucks up interfaces between various
modules. The only current way around it that you can really rely on
being portable is to use counted pointers, but then counted pointers can
*bleep* you if your not careful about your cycles.
>
> For instance, how would you make this legal:
> GC_ptr<Foo>x = new Foo;
> (*x).FooFunc();
> but keep this illegal:
> Foo*vanilla = &*x;
>
> Also, how would you differentiate the "good" line in your example
> that I've marked "Line A" from the "error" line that I marked
> "Line B"? In each case we have a GC_ptr<int> being assigned a value
> of type int*.
>
> In general, we would need to devise a set of rules regulating the
> interaction between T* and GC_ptr<T>.
This is because it makes more sense to specify garbage collection in
terms of the types as well as the pointers. For example, if you have
class A and you want it to be garbage collected, then perhaps you
define it as:
class A : public B, collected { .... } ;
now class A is specified as a garbage collected class. Now it is
possible to make clear distinctions between your GC objects and non GC
objects. If you want to take the address of class A, then you must
use a GC_ptr, non-GC_ptr and GC_ptr types are not interchangeable and
the system doesn't let them be exchanged. Now you know that all
GC_ptr's contain pointers to GC objects and that nothing that isn't a
GC_ptr isn't refering to a GC object. Also, the GC would have to
actually call the destructor to release memory since these GC objects
may contain non-GC pointers that need to be released. Of course this
makes it impossible to have a garbage collected integer, but no big
deal, garbage collecting integers isn't very interesting anyways.
The reason you would add this capability would be to facilitate
passing large objects between various modules without copying them and
without concerning each module with details of how to manage the
destructors of these objects. This simplifies the design of these
interactions significantly while allowing these large objects to be
efficiently placed in rather complex, possibly cyclical, data and
control structures.
___________________________________________________________________
Ed Luke lush@erc.msstate.edu
NSF Engineering Research Center for Computational Field Simulations
Mississippi State University http://www.erc.msstate.edu/~lush
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/14 Raw View
In <77f484$est$1@rocky.jgk.org>, Joe Keane <jgk@jgk.org> writes:
>Garbage collection is dumb.
I have written many C/C++ programs where memory management
was very complex. Garbage collection would certainly have helped
in some of those programs. In one of them, which relied very
heavily on heap-allocated objects, I found that the standard
memory allocation routines were consuming some 80% of all cpu
resources for the program. Even a poor garbage collector would
probably not consume more than 10%.
While garbage collection is not necessary for all programs, I
certainly wish I had it available as part of the language standard
(so that my code would also be portable -- that is a problem
with add-on garbage collectors). It should, of course, be turned
on or off by an option or pragma.
In short, garbage collection is *not* dumb!
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mfinney@lynchburg.net
Date: 1999/01/14 Raw View
In <3694C2D1.7ED3@pratique.fr>, Valentin Bonnard <bonnardv@pratique.fr> writes:
>> Specifically, I feel uneasy not knowing
>> if a destructor will ever be called.
>As no one has mentionned it yet, I want to cite BS opinion
>on this: gc models infinite memory in a finite computer:
>you never free memory, but as you have infinite memory, you
>don't get a bad_alloc (well, you can get a bad_alloc, but
>latter than w/o gc). When you never delete things, dtors
>are never called, so a gc shouldn't try to call dtors of
>collected objects.
I think that that finialization problem is reasonably trivial. It
can be handled in the following manner...
1. The vptr for all objects precede the object. This is
not mandated by the C++ standard, but is allowed as I understand
the standard (this has a lot of advantages and I am surprised that
nobody is doing it this way (to the best of my knowledge, of course)).
2. All heap allocated objects always have a vptr which precedes the
object, even if the object is not virtual and a pointer to the destructor
is always in the vptr. That does not need to cause an increase in
memory usage because most storage managers allocate at least
4-bytes of overhead for an object to indicates its length. That length
can be embedded in the vptr table.
3. There is a special vptr for "dead" objects which is not
directly available to the programmer. However, when delete is
run on an object, after it finishes, the vptr is replaced with the
dead vptr and the object's length can be placed in the first 4 bytes
of the object. Then, any reference to a virtual function of a
deleted object could be cleanly detected by causing all such
methods to throw an exception. Calling the destructor for a
dead object does nothing.
4. When the garbage collector runs, it always calls the
destructor for that object. If the object is dead then it will be
finialized at that point. However, the programer retains explicit
control over when finialization occurs. That solves the problem
of dangling resources other than memory which need to be
released immediately.
The garbage collection can "batch" the finialization calls after
it detects garbage, but before changing anything. This approach
may mean that some objects would become dead during that
phase, but not be detected until the next sweep. That shouldn't
be a problem, and it could probably be overcome -- if nothing
else, the number of nearly dead objects could be counted and if the
count after running the finialization pass is greater then extra
objects died and another finialization pass could be made. I would
probably chose to let the extra dead objects languish until the next
sweep.
The above approach does require compiler cooperation, but I highly
recommend that anyway. It also means that the problem with the
compiler optimizing away pointers to blocks could be avoided in the
first place.
Finially, I would suggest that when garbage collection is turned on
that the language require a few extra rules...
1. Pointers, like refereces, are not allowed in unions.
2. Pointers cannot be assigned to integral values. It would be o.k. to
allow the assignment in the other direction so that pointers can be
set to fixed locations in memory, and it would even be possible to
manage storage using unsigned longs -- including doing things like
handling alignment issues -- and then assign the result to a pointer.
3. reinterpret-cast and the older style casts would not be allowed to
cast a pointer to an integral value.
Perhaps other constraints would be desirable, but even these
constraints are options as the existence of conservative collectors
has shown.
This could cause behaviour change in that non-virtual destructors
would become virtual for heap-allocated objects, but I am not
really sure that is a significant problem. Is there ever a case when
you really want a slicing destructor?
Michael Lee Finney
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/07 Raw View
Tom Payne wrote:
>
> Valentin Bonnard (bonnardv@pratique.fr) wrote:
> : AllanW@my-dejanews.com wrote:
> : >
> : > In article <3690FD0E.188D@pratique.fr>,
> : > Valentin Bonnard <bonnardv@pratique.fr> wrote:
>
> : > > char * p = malloc (100);
> : > > const unsigned long magic = 0x12345678;
> : > > if (sizeof p >= sizeof magic)
> : > > reinterpret_cast<unsigned long&> (p) ^= magic;
> : > > sleep (100);
> : > > if (sizeof p >= sizeof magic)
> : > > reinterpret_cast<unsigned long&> (p) ^= magic;
> : > > free (p);
>
> : > You should be more explicit, of course; the proposal is too
> : > ambiguous.
>
> : It isn't a proposal ! I was simply giving an example which
> : would be broken by a gc.
>
> Is this example "conforming"?
Allmost. Sufficiently to seriously consider this sort of code
(that's just an example; if you don't like it, take another
one). One _can_ encript pointers and so any gc is non conforming
today. We could work on forbiding hiden pointers.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Miniussi <miniussi@ilog.fr>
Date: 1999/01/07 Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <3691E273.DC82B7A3@ilog.fr>,
> Miniussi <miniussi@ilog.fr> wrote:
>
> > A real "problem" would be something like:
> >
> > char* p = malloc(100);
> > int offset = 42;
> > p -= offset;
> > [...]
> > p +=offset;
> >
> > since it's valid, [...]
> It's not valid.
I know, 5.7(5) but I didn't 2 days ago, why should I spend my time checking
the compliance of code I won't write ? Now I know the answer :-)
> If you write it,
I don't.
> On the other hand, as I pointed out in another posting, the compiler is
> free to generate things like this internally, which means that a
> conservative garbage collector might not work with some specific
> compiler.
It could be a good reason to talk about it the standard.
> I suspect that the big problem with garbage collection is going to be in
> distributed systems.
Distributed garbage collection technics already exists, which doesn't
influence the choice of locals GC. So if there is a problem (and
maybe there is, in practice) I think it does not concern the standard.
> > I'm surprised that no one talked about finalization yet, since I think
> > that a big issue if you want some pseudo standard way to handle GC in
> > C++.
>
> Perhaps because finalization is a red herring. Instead of calling
> "delete p", you call "p->finalize()". Big deal.
Or the GC call it, which can involve registering objects with weak
pointers, which involve somes other question since finalizer can make
"this" reachable, since there is a cost etc.
I wasn't talking about the syntaxic difference.
> In fact, IMHO,
> finalization should usually be separate from memory deallocation.
Maybe, and maybe not, I think it's an issue, I'm not sure of the answer.
Well.. I think that if it remain something in the destructor once the
memory mangement part has been remove, it's probably not wise to let
a conservative GC to do the call. Specially if you consider the fact that
you don't know when it will be called, and if it will be called: what real job
can it be then ? So I think that automatic finalization during collection
is not a good idea for C++ (I don't think it works in Java either, but
that's another point), but it doesn't prevent it from being an issue
in that context.
> (I've seen more memory leaks in two months of Java than in 15 years of
> C/C++. So much for silver bullets.)
Are you saying that you actually believed the Java propaganda ? :-)
Alain
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/01/07 Raw View
AllanW@my-dejanews.com writes:
>Personally, I will consider using GC when someone solves the problem
>of how GC-released memory can call destructors first.
I don't think anyone will ever come up with a solution to this problem
that will satisfy everyone in the case of cyclic data structures.
With a cyclic data structure, when destroying the second object, any
pointers to the first object will be dangling pointers, since the first
object will have already been destroyed. This can clearly lead to problems.
Of course you can use weak pointers to avoid such problems,
but if you're willing to modify your code to use weak pointers,
you might as well modify it to use finalizers too, where necessary.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh> | but source code lives forever"
PGP: finger fjh@128.250.37.3 | -- leaked Microsoft memo.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Miniussi <miniussi@ilog.fr>
Date: 1999/01/07 Raw View
Pete Becker wrote:
>
> Scott Johnson wrote:
> >
> >
> > More aggressive garbage collectors, such as what Java uses, depend on
> > knowing where all the pointers are.
>
> The Java language definition does not prohibit the use of a conservative
> collector. Some implementations use a conservative collector, some
> don't.
Actualy, I think that the first version of the native methode interface
(before JNI) required it to be conservative since you could hold
pointer to Java Objects in the native code. Still, you can distinguish
a Java integer from a Java pointer, which is not that easy in C++ if you
don't have collaboration from the compiler or preprocessing. (there are
some technics that can help, but I only saw one ref (a paper by Paul Wilson)
I think and no commercial implementation.
(maybe there is a more appropriate newsgroup ?)
[ moderator's note: This thread is about GC and whether it is
appropriate for C++, and if so, how it could be defined and
implemented -- all suitable for this newsgroup. Discussing
how GC is done in other languages is also suitable when it
is for the purpose of illuminating the topic. -sdc ]
Alain
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/01/07 Raw View
In article <7711g5$jup$1@nnrp1.dejanews.com>, AllanW@my-dejanews.com
says...
[ .... ]
> That isn't really a cost. We're talking about either including
> conservative GC or excluding it. Either way, we don't compact memory
> blocks in C++.
I meant it's a cost of conservative collection vs. supported
collection (for lack of a better term).
> The fact that some other language has more support for GC, which
> allows it to transparently compact memory blocks, isn't really
> relevant unless you propose doing the same thing in C++. But this
> would require compiler support. For some reason that escapes me,
> nobody wants to consider GC that requires compiler support.
I'm not sure -- a year or two ago, there was talk of a version of gcc
including a garbage collector, but that seems to have been abandoned.
While C++ may make supporting a garbage collector a _bit_ more
difficult than some other languages, since it supports the pointer
swizzling and such that have already been mentioned, there's very
little difference in most respects.
The one major problem that will arise is if you plan on storing a
pointer in an int, or long, or some other type that happens to be
large enough on some particular implementation or other. At one time,
this was fairly common, and some people may still do it. Hopefully
any worthwhile compiler already gives a warning for doing such a
thing, and GC support in the compiler would turn such a warning into
an error.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: thp@vdo.ucr.edu (Tom Payne)
Date: 1999/01/08 Raw View
Valentin Bonnard (bonnardv@pratique.fr) wrote:
: Tom Payne wrote:
: >
: > Valentin Bonnard (bonnardv@pratique.fr) wrote:
: > : AllanW@my-dejanews.com wrote:
: > : >
: > : > In article <3690FD0E.188D@pratique.fr>,
: > : > Valentin Bonnard <bonnardv@pratique.fr> wrote:
: >
: > : > > char * p = malloc (100);
: > : > > const unsigned long magic = 0x12345678;
: > : > > if (sizeof p >= sizeof magic)
: > : > > reinterpret_cast<unsigned long&> (p) ^= magic;
: > : > > sleep (100);
: > : > > if (sizeof p >= sizeof magic)
: > : > > reinterpret_cast<unsigned long&> (p) ^= magic;
: > : > > free (p);
: >
: > : > You should be more explicit, of course; the proposal is too
: > : > ambiguous.
: >
: > : It isn't a proposal ! I was simply giving an example which
: > : would be broken by a gc.
: >
: > Is this example "conforming"?
: Allmost. Sufficiently to seriously consider this sort of code
: (that's just an example; if you don't like it, take another
: one). One _can_ encript pointers and so any gc is non conforming
: today. We could work on forbiding hiden pointers.
If gc breaks a nonconforming example, it is of no concern. Are there
conforming ways of hiding and restoring a pointer, such that the
restored pointer is dereferencable?
Tom Payne
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/09 Raw View
Tom Payne wrote:
> Are there
> conforming ways of hiding and restoring a pointer, such that the
> restored pointer is dereferencable?
A pointer is a POD, so it's just a bag od bits and you can play
with its bits as much as you want.
This includes xor-ing, writing to a file, encription...
This is _clearly_ legal, even if the std doesn't really define
when a program has undefined behaviour.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ruslan@Shevchenko.Kiev.UA
Date: 1999/01/09 Raw View
> If gc breaks a nonconforming example, it is of no concern. Are there
> conforming ways of hiding and restoring a pointer, such that the
> restored pointer is dereferencable?
>
what I can't understood: why not use something like
gc_ptr<..> for garbage-collected pointers ?
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: thp@vdo.ucr.edu (Tom Payne)
Date: 1999/01/10 Raw View
Valentin Bonnard (bonnardv@pratique.fr) wrote:
: Tom Payne wrote:
: > Are there
: > conforming ways of hiding and restoring a pointer, such that the
: > restored pointer is dereferencable?
: A pointer is a POD, so it's just a bag od bits and you can play
: with its bits as much as you want.
: This includes xor-ing, writing to a file, encription...
: This is _clearly_ legal, even if the std doesn't really define
: when a program has undefined behaviour.
My concern arose from the fact that in C (and AFIK in C++) the result
of converting an integer to a pointer is explicitly "implementation
defined." Bill Wade points out, however, that we can just as well use
memcpy to set the state of the pointer.
I'm convinced.
Tom Payne
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/01/10 Raw View
Tom Payne wrote:
....
> If gc breaks a nonconforming example, it is of no concern. Are there
> conforming ways of hiding and restoring a pointer, such that the
> restored pointer is dereferencable?
Of course, lots of them, most of which have been mentioned several times
on this thread. The most extreme example is writing it to a file, and
then reading it back again.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/01/10 Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:
>Tom Payne wrote:
>> Are there
>> conforming ways of hiding and restoring a pointer, such that the
>> restored pointer is dereferencable?
>A pointer is a POD, so it's just a bag od bits and you can play
>with its bits as much as you want.
>This includes xor-ing, writing to a file, encription...
>This is _clearly_ legal, ...
Well, not really.
You cannot perform bitwise operations on a pointer. You must
first convert the pointer to an integer type. The standard
says that if a suitable integer type exists, you can convert the
pointer value to that type and back to the original type
and the result compares equal to the original.
The standard does not promise that the integer type exists,
although such a type usually exists. (An exception would be
an AS400 platform with 32-bit longs and 48-bit pointers,
and no "long long" type.)
If you can perform the conversion to an integer type, the
standard makes no promises about what happens if you modify
the bits and try to store the result back into a pointer type.
Some platforms have hardware checks on pointers, and trying to
store an invalid pointer results in a program trap. Such an
implementation conforms to the standard.
On many popular platforms you can swizzle pointers without any
problem, but (particularly in comp.std.c++) we have to be careful
about calling the operation valid or portable.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1999/01/10 Raw View
Miniussi <miniussi@ilog.fr> writes:
|> James.Kanze@dresdner-bank.com wrote:
|> > I suspect that the big problem with garbage collection is going to be in
|> > distributed systems.
|>
|> Distributed garbage collection technics already exists, which doesn't
|> influence the choice of locals GC. So if there is a problem (and
|> maybe there is, in practice) I think it does not concern the standard.
That's not what I was worried about. What I was concerned about is the
na ve coders who are going to implement the distributed system using
process specific addresses (the contents of a T*) as the distributed
object id, without any in process mapping or such. In such cases, it
would not be surprising if all of the references to an object were in
other processes, which would allow garbage collection to collect it.
IMHO, this is simply bad design -- it has no degree of resiliance
whatsoever, and the first process (or machine) that goes down corrupts
the entire system, which sort of defeats one of the main purposes of
distributing. But I would hardly be surprised if any number of people
do it.
|> > > I'm surprised that no one talked about finalization yet, since I think
|> > > that a big issue if you want some pseudo standard way to handle GC in
|> > > C++.
|> >
|> > Perhaps because finalization is a red herring. Instead of calling
|> > "delete p", you call "p->finalize()". Big deal.
|>
|> Or the GC call it, which can involve registering objects with weak
|> pointers, which involve somes other question since finalizer can make
|> "this" reachable, since there is a cost etc.
But that really doesn't solve the finalization problem. The real
"problem" is that finalization must sometimes take place at a fixed
moment. If I click on the close button on a window, I don't want the
window to hang around on the screen until garbage collection happens to
pick up the memory.
On the other hand, I find that using "delete p" to invoke finalization,
while a convenient shortcut, is often mixing two issue that should be
kept separate. Suppose that for some reason, the window cannot be
closed: what happens if "delete p" is used?
|> Are you saying that you actually believed the Java propaganda ? :-)
I've never believed in silver bullets. On the other hand, judging from
any number of postings in some of the Java groups, a lot of other people
do. (Worse, judging from the implementation of the latest Java
windowing interface, Swing, some of the Java implementers do as well.)
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient e objet --
-- Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1999/01/10 Raw View
thp@vdo.ucr.edu (Tom Payne) writes:
|> If gc breaks a nonconforming example, it is of no concern. Are there
|> conforming ways of hiding and restoring a pointer, such that the
|> restored pointer is dereferencable?
Sure.
Copy the pointer to a buffer (unsigned char[]) using memcpy. Compress
the buffer using LZW (or any other compression algorithm). Do a lot of
other things, triggering GC. Decompress the buffer, and copy the
pointer back using memcpy.
Write the pointer to a file. Read it back later.
Send the pointer to another process. Read it back later.
Write the pointer in hex to the screen. Have the user type it back in
later.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient e objet --
-- Beratung in objektorientierter Datenverarbeitung
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/01/11 Raw View
Steve Clamage wrote:
>
> Valentin Bonnard <bonnardv@pratique.fr> writes:
>
> >Tom Payne wrote:
....
> >A pointer is a POD, so it's just a bag od bits and you can play
> >with its bits as much as you want.
>
> >This includes xor-ing, writing to a file, encription...
>
> >This is _clearly_ legal, ...
>
> Well, not really.
>
> You cannot perform bitwise operations on a pointer. You must
> first convert the pointer to an integer type. The standard
> says that if a suitable integer type exists, you can convert the
> pointer value to that type and back to the original type
> and the result compares equal to the original.
>
> The standard does not promise that the integer type exists,
.....
However, something that you can always do, with similar effects, is:
memcpy the pointer into an equal-size array of unsigned char, with
arbitrary alignment. Replace the original pointer with something else.
Fiddle with the bits in that array. Undo the fiddling. Copy back to the
pointer. Dereference the pointer (assuming it was originally
dereferencable). I don't think any GC could cope with that except by
saying "don't do that".
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: markw65@my-dejanews.com
Date: 1999/01/11 Raw View
In article <778abf$m1e$1@engnews2.Eng.Sun.COM>,
clamage@Eng.Sun.COM (Steve Clamage) wrote:
> Valentin Bonnard <bonnardv@pratique.fr> writes:
>
> >Tom Payne wrote:
>
> >> Are there
> >> conforming ways of hiding and restoring a pointer, such that the
> >> restored pointer is dereferencable?
>
> >A pointer is a POD, so it's just a bag od bits and you can play
> >with its bits as much as you want.
>
> >This includes xor-ing, writing to a file, encription...
>
> >This is _clearly_ legal, ...
>
> Well, not really.
>
> You cannot perform bitwise operations on a pointer. You must
> first convert the pointer to an integer type. The standard
> says that if a suitable integer type exists, you can convert the
> pointer value to that type and back to the original type
> and the result compares equal to the original.
>
> The standard does not promise that the integer type exists,
> although such a type usually exists. (An exception would be
> an AS400 platform with 32-bit longs and 48-bit pointers,
> and no "long long" type.)
But you can do the "conversion" yourself:
T* p = <whatever>;
char buffer[sizeof(p)];
memcpy(buffer, &p, sizeof(p));
<scramble buffer>
p = 0;
<wait for garbage collection>
<unscramble buffer>
memcpy(&p, buffer, sizeof(p));
Mark Williams
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/12 Raw View
Steve Clamage wrote:
>> ...
>> You cannot perform bitwise operations on a pointer. You must
>> first convert the pointer to an integer type. The standard
>> says that if a suitable integer type exists, you can convert the
>> pointer value to that type and back to the original type
>> and the result compares equal to the original.
James Kuyper wrote:
> ...
> However, something that you can always do, with similar effects, is:
> memcpy the pointer into an equal-size array of unsigned char, with
> arbitrary alignment. Replace the original pointer with something else.
> Fiddle with the bits in that array. Undo the fiddling. Copy back to
> the
> pointer. Dereference the pointer (assuming it was originally
> dereferencable). I don't think any GC could cope with that except by
> saying "don't do that".
I haven't followed all of this thread, so perhaps this has already
been suggested, but...
Has anyone proposed a special pointer class that would be used for
GC, apart from built-in pointer types? For example:
template <class T>
class GC_ptr // Perhaps declared in <stdlib>
{ ... };
void myfunc()
{
GC_ptr<int> ip; // Points to a GC'd int
int i;
ip = new int[100];
// Do things with ip, *ip, and ip[i]
*ip = 123;
ip[20] = -69;
i = ip[20];
printf("%d", *ip);
ip[0] += ip[99] / *ip;
foo(ip, 100);
// Do illegal things with ip
ip++; // Error
ip += 50; // Error
reinterprest_cast<long&>(ip) ^= SCRAMBLE; // Error
int * jp = ip; // Error, removes GC-ness of the int
ip = jp; // Error
ip = NULL; // Error (or maybe not?)
// Don't need explicit delete, GC will handle it
// delete ip;
}
We could go further and state that the destructor for the object
pointed to by a GC_ptr will get invoked at an unspecified time
during program execution (which makes a GC_ptr different from an
auto_ptr). We limit the legal operations on GC_ptr objects,
so that things like previous posts mentioned (such as scrambling
the bits of the pointer, and incrementing the pointer momentarily
out of existence) simply won't happen.
This also solves the problem of mixing code with and code without
GC (such as third-party libraries), since only code that uses
GC_ptr objects will have (or need) GC.
Or have I missed something?
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/12 Raw View
In article <369AA8AF.EFB0CD68@technologist.com>,
David R Tribble <dtribble@technologist.com> wrote:
> Has anyone proposed a special pointer class that would be used for
> GC, apart from built-in pointer types? For example:
>
> template <class T>
> class GC_ptr // Perhaps declared in <stdlib>
> { ... };
>
> void myfunc()
> {
> GC_ptr<int> ip; // Points to a GC'd int
> int i;
>
//////// Line A:
> ip = new int[100];
>
> // Do things with ip, *ip, and ip[i]
> *ip = 123;
> ip[20] = -69;
> i = ip[20];
> printf("%d", *ip);
> ip[0] += ip[99] / *ip;
> foo(ip, 100);
>
> // Do illegal things with ip
> ip++; // Error
> ip += 50; // Error
> reinterprest_cast<long&>(ip) ^= SCRAMBLE; // Error
> int * jp = ip; // Error, removes GC-ness of the int
//////// Line B:
> ip = jp; // Error
> ip = NULL; // Error (or maybe not?)
>
> // Don't need explicit delete, GC will handle it
> // delete ip;
> }
>
> We could go further and state that the destructor for the object
> pointed to by a GC_ptr will get invoked at an unspecified time
> during program execution (which makes a GC_ptr different from an
> auto_ptr). We limit the legal operations on GC_ptr objects,
> so that things like previous posts mentioned (such as scrambling
> the bits of the pointer, and incrementing the pointer momentarily
> out of existence) simply won't happen.
>
> This also solves the problem of mixing code with and code without
> GC (such as third-party libraries), since only code that uses
> GC_ptr objects will have (or need) GC.
>
> Or have I missed something?
You've missed the "G" in "GC". Your idea is a clever *alternative*
to Garbage Collection. People asking for GC are asking for a method
to reclaim memory from ANY object that can no longer be accessed.
You've restricted this to a special group of allocated items.
Essentially you've encapsulated a reference-counted pointer. The
implementation of GC_ptr<T> would use a lower-level class which
contains the T* and the reference count. When the reference
count goes to 0, the lower-level class destroys the T and then
destroys itself.
This can be useful in many situations where some people are
asking for GC, i.e.
{
GC_ptr<int> a = new int[10];
GC_ptr<int> b = a;
a[0]=1,a[2]=4,a[4]=8;
// ...
a = new int[2]; // Original allocation still held in b
a[0] = b[0]+b[2];
b = NULL; // Releases original allocation
// (No, this is not an error!)
} // a and b go out of scope
// No remaining pointers to second allocation, so it's released
This is very useful, but there are some technical problems related
to the interaction to "plain vanilla" pointers and GC_ptr's.
For instance, how would you make this legal:
GC_ptr<Foo>x = new Foo;
(*x).FooFunc();
but keep this illegal:
Foo*vanilla = &*x;
Also, how would you differentiate the "good" line in your example
that I've marked "Line A" from the "error" line that I marked
"Line B"? In each case we have a GC_ptr<int> being assigned a value
of type int*.
In general, we would need to devise a set of rules regulating the
interaction between T* and GC_ptr<T>.
---
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/12 Raw View
Pete Forman <gsez020@compo.bedford.waii.com> wrote:
>> I recall seeing code like this in C to simulate one based indexing.
>>
>> int * int_vector(size_t s) {
>> int *p = malloc(s * sizeof(int));
>> return p ? p - 1 : 0;
>> }
>>
>> void free_int_vector(int *p) {
>> if (p) free (p + 1);
>> return;
>> }
James.Kanze@dresdner-bank.com wrote:
> I've seen lots of wrong code, too. The above is simply undefined
> behavior, according to both the C and the C++ standards.
A simple change makes it conforming, though:
int * int_vector(size_t s)
{
int * p = malloc(s * sizeof(int));
return (p ? p+1 : 0); // defined
}
void free_int_vector(int *p)
{
if (p)
free(p-1); // defined
}
int main()
{
free_int_vector(int_vector(20));
return 0;
}
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/12 Raw View
Jerry Coffin wrote:
> ... a year or two ago, there was talk of a version of gcc
> including a garbage collector, but that seems to have been abandoned.
> While C++ may make supporting a garbage collector a _bit_ more
> difficult than some other languages, since it supports the pointer
> swizzling and such that have already been mentioned, there's very
> little difference in most respects.
>
> The one major problem that will arise is if you plan on storing a
> pointer in an int, or long, or some other type that happens to be
> large enough on some particular implementation or other. At one time,
> this was fairly common, and some people may still do it. Hopefully
> any worthwhile compiler already gives a warning for doing such a
> thing, and GC support in the compiler would turn such a warning into
> an error.
No one has made the obvious suggestion, so I will...
There is nothing to prevent a C++ compiler from implementing
pointers as "heavy pointers", i.e., having extra information in
them which would be used by a smart GC mechanism. Distiguishing
real pointers from objects whose bit pattern look like pointers
then becomes a lot less problematic.
It's also possible (and reasonable in the majority of code) to
illegalize casting pointers to and from integers. Or at least
advertise it as dangerous in a GC system.
Yes, heavy pointers are more expensive, but it's reasonable to
assume that (many) programmers are willing to pay a little extra
for good GC. (Look at Java.)
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Joe Keane <jgk@jgk.org>
Date: 1999/01/12 Raw View
In article <m3iueg6n2e.fsf@gabi-soft.fr>
J. Kanze <kanze@gabi-soft.fr> writes:
>That's not what I was worried about. What I was concerned about is the
>[naive] coders who are going to implement the distributed system using
>process specific addresses (the contents of a T*) as the distributed
>object id, without any in process mapping or such. In such cases, it
>would not be surprising if all of the references to an object were in
>other processes, which would allow garbage collection to collect it.
Garbage collection is dumb.
>IMHO, this is simply bad design -- it has no degree of resiliance
>whatsoever, and the first process (or machine) that goes down corrupts
>the entire system, which sort of defeats one of the main purposes of
>distributing. But I would hardly be surprised if any number of people
>do it.
I don't think many people send pointers around. More likely, they use
some sort of opaque IDs, such as an integer or a tuple of integers, and
each process has a table mapping from these to pointers.
Now garbage collection sees the pointers. The problem is, it sees the
pointers. It has no clue whether IDs are in use. So we do all the work
for garbage collection, and it takes time and space to do its thing, and
it figures out something that we know already, and we're back where we
started, trying to figure out when to free resources.
>But that really doesn't solve the finalization problem. The real
>"problem" is that finalization must sometimes take place at a fixed
>moment. If I click on the close button on a window, I don't want the
>window to hang around on the screen until garbage collection happens to
>pick up the memory.
Well that's the thing about garbage collection, it tries to figure out
when to free memory. It doesn't do so well, always freeing stuff late,
but ignoring that, the main thing is, it does nothing for anything else.
There are lots of things that are extremely similar: you open a file,
you close it; you allocate memory, you free it; you map shared memory,
you unmap it; you increment a counter, you decrement it.
See a pattern here? Should i continue?
If you have some scheme that solves one of these problems, and you need
something else entirely for the next one, how much does it help really?
>On the other hand, I find that using "delete p" to invoke finalization,
>while a convenient shortcut, is often mixing two issue that should be
>kept separate. Suppose that for some reason, the window cannot be
>closed: what happens if "delete p" is used?
You are right. C++ is dumb too.
See the `exception from destructor' thread for more about this.
IMHO, it's a fatal flaw that destruction has no provision for errors.
That is a basic coding guideline, every function returns an error code.
>I've never believed in silver bullets. On the other hand, judging from
>any number of postings in some of the Java groups, a lot of other people
>do. (Worse, judging from the implementation of the latest Java
>windowing interface, Swing, some of the Java implementers do as well.)
Java is dumb too.
The good thing about all this stuff is that it doesn't work.
People get some urge to use all this new stuff and make something really
nifty, and they work on it a lot, and it seems to work sort of, but it
crashes now and then, and in truth it's really bloated and slow, and it
has leaks that no one can figure out, and come to think of it, they
spend much more time trying to make it work than anyone should.
Meanwhile some of us program in C, and we call `malloc' and `free', and
we're surely just Neanderthals for this, but we write stuff that people
use every day and the stuff just works. And we tell these other people,
yes you are very clever, much more than us, and please get back to us
when routing and mail and Web service is done on your Lisp machines.
--
Joe Keane, amateur mathematician
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/12 Raw View
Miniussi <miniussi@ilog.fr> wrote:
>> A real "problem" would be something like:
>>
>> char* p = malloc(100);
>> int offset = 42;
>> p -= offset;
>> [...]
>> p +=offset;
>>
>> since it's valid, does not use reinterpret_cast, and leave the whole
>> piece of memory unreferenced.
James.Kanze@dresdner-bank.com wrote:
> It's not valid. If you write it, it is undefined behavior.
Simple changes makes it conforming, though:
char * p = malloc(100);
int offset = 42;
p += offset; // defined, points into p[]
... // [A]
p -= offset; // defined, points to original p[0]
A working GC should not free the block pointed at by p during [A],
even if p isn't pointing at the block's base address.
-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/13 Raw View
In article <369B979C.346963CE@technologist.com>,
David R Tribble <dtribble@technologist.com> wrote:
>
> Pete Forman <gsez020@compo.bedford.waii.com> wrote:
> >> I recall seeing code like this in C to simulate one based indexing.
> >>
> >> int * int_vector(size_t s) {
> >> int *p = malloc(s * sizeof(int));
> >> return p ? p - 1 : 0;
> >> }
> >>
> >> void free_int_vector(int *p) {
> >> if (p) free (p + 1);
> >> return;
> >> }
>
> James.Kanze@dresdner-bank.com wrote:
> > I've seen lots of wrong code, too. The above is simply undefined
> > behavior, according to both the C and the C++ standards.
>
> A simple change makes it conforming, though:
>
> int * int_vector(size_t s)
> {
> int * p = malloc(s * sizeof(int));
> return (p ? p+1 : 0); // defined
> }
>
> void free_int_vector(int *p)
> {
> if (p)
> free(p-1); // defined
> }
>
> int main()
> {
> free_int_vector(int_vector(20));
> return 0;
> }
What was this code supposed to demonstrate?
Pete's point was that there may be some useful code out there, where
some memory is allocated and used, but we don't keep a pointer to
anywhere in the block. His specific example solved problems common
to code that has been translated from certain other high-level
languages, for instance certain dialects of BASIC, where the lowest
valid index in an array is 1 instead of 0. Note that the pointer p
could have been used as:
p[1] = p[2] + p[3];
instead of
p[0] = p[1] + p[2];
In your replacement, we have the bizzare replacement of an array whose
lowest bound is NEGATIVE 1! So you would write
p[-1] = p[0] + p[1];
which is probably of very little use. Furthermore, it no longer
qualifies as an example of an allocated block without pointers to
someplace in the block. It's true that p doesn't point to the
beginning of the block anymore, but it does generally point inside
the block (or to the end of the block, if int_vector is called with
s==1).
If this is on-topic, please explain how.
---
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Alex Martelli" <martelli@cadlab.it>
Date: 1999/01/04 Raw View
Luca Arzeni wrote in message <01be3599$6e891aa0$e2b8d8d4@default>...
[snip]
>I've still not tested it, but the strong pointers seems to be an
>interesting idea. I suggest you to take a look at www.resource.com, by
>Milewski.
The site in question seems mostly devoted to a review of
"Victoria's Secret" web pages, including an Online Shop,
"Bra Salon", "never-before-seen footage of fashion
models" and so on -- what "strong pointers" is supposed
to mean in this context sort of escapes me, but perhaps
Mr Arzeni might be kind enough to clarify...?
Alex
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/04 Raw View
Bjarne Stroustrup wrote:
> There was a lot of talk about a variety of garbage collection schemes.
> I favor optional garbage collection based on conservative collectors.
> I consider such collectors conforming and I proposed that the standard
> explicitly say so. The explicit statement was voted down, but I still
> see nothing that prohibits conservative garbage collectors for C++.
> That's good because there are free and commercial versions in fairly
> widespread use.
char * p = malloc (100);
const unsigned long magic = 0x12345678;
if (sizeof p >= sizeof magic)
reinterpret_cast<unsigned long&> (p) ^= magic;
sleep (100);
if (sizeof p >= sizeof magic)
reinterpret_cast<unsigned long&> (p) ^= magic;
free (p);
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/05 Raw View
In article <3690FD0E.188D@pratique.fr>,
Valentin Bonnard <bonnardv@pratique.fr> wrote:
>
> Bjarne Stroustrup wrote:
>
> > There was a lot of talk about a variety of garbage collection schemes.
> > I favor optional garbage collection based on conservative collectors.
> > I consider such collectors conforming and I proposed that the standard
> > explicitly say so. The explicit statement was voted down, but I still
> > see nothing that prohibits conservative garbage collectors for C++.
> > That's good because there are free and commercial versions in fairly
> > widespread use.
>
> char * p = malloc (100);
> const unsigned long magic = 0x12345678;
> if (sizeof p >= sizeof magic)
> reinterpret_cast<unsigned long&> (p) ^= magic;
> sleep (100);
> if (sizeof p >= sizeof magic)
> reinterpret_cast<unsigned long&> (p) ^= magic;
> free (p);
Your point, perhaps, is that the C++ standard should include
a new library function, called sleep, which accepts an integer
argument -- and this has something to do with GC? Perhaps it
reclaims apparently-discarded blocks that are 100 bytes or
larger, or reclaims all blocks unless there's at least one
free block (already allocated from the OS, if appropriate,
but not currently in use) of 100 bytes or more?
You should be more explicit, of course; the proposal is too
ambiguous. You should also pick a more appropriate name;
sleep sounds like something for a multitasking OS (allow
other tasks to run), but this has little to do with GC.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/05 Raw View
AllanW@my-dejanews.com wrote:
>
> In article <3690FD0E.188D@pratique.fr>,
> Valentin Bonnard <bonnardv@pratique.fr> wrote:
> >
> > Bjarne Stroustrup wrote:
> >
> > > There was a lot of talk about a variety of garbage collection schemes.
> > > I favor optional garbage collection based on conservative collectors.
> > > I consider such collectors conforming and I proposed that the standard
> > > explicitly say so. The explicit statement was voted down, but I still
> > > see nothing that prohibits conservative garbage collectors for C++.
> > > That's good because there are free and commercial versions in fairly
> > > widespread use.
> >
> > char * p = malloc (100);
> > const unsigned long magic = 0x12345678;
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > sleep (100);
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > free (p);
>
> Your point, perhaps, is that the C++ standard should include
> a new library function, called sleep, which accepts an integer
> argument -- and this has something to do with GC? Perhaps it
> reclaims apparently-discarded blocks that are 100 bytes or
> larger, or reclaims all blocks unless there's at least one
> free block (already allocated from the OS, if appropriate,
> but not currently in use) of 100 bytes or more?
>
> You should be more explicit, of course; the proposal is too
> ambiguous. You should also pick a more appropriate name;
> sleep sounds like something for a multitasking OS (allow
> other tasks to run), but this has little to do with GC.
Valentin's point is that by engaging in such gratitious
pointer-swizzling, one can easily fool even a conservative garbage
collector. If the GC runs during the sleep() interval, it may
find no valid pointers pointing to the storage allocated in the first
line, and reclaim such storage. In which case when the pointer
gets unswizzled, it now is a stray.
Whether this is actually a problem, or whether the behavior of
Valentin's example is sufficiently pathological to be ignored, is a
matter of debate.
More troublesome is this bit of code, which is more "reasonable".
void reverse_100 (void) {
char * p = malloc (100);
int i=0;
for (i = 0; i < 100; ++i) {
*(p++) = getchar();
}
for (i = 99; i >= 0; --i. --p) {
putchar (*(--p));
}
free (p);
}
Obviously, there are better ways to write this function, and it too is
offered as an example. OTOH, this sort of code is more likely to be
encountered in real life; tis not uncommon at all to traverse an array
without maintaining a pointer to the base of the array. At all points
in the program, p points to a valid member of the array, or to the "one
past the end" location...however, if the GC runs in the middle (likely
as I/O is being done), it may find no valid pointers to the array, and
trash the array.
Scott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jonathan Biggar <jon@floorboard.com>
Date: 1999/01/05 Raw View
AllanW@my-dejanews.com wrote:
> > char * p = malloc (100);
> > const unsigned long magic = 0x12345678;
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > sleep (100);
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > free (p);
>
> Your point, perhaps, is that the C++ standard should include
> a new library function, called sleep, which accepts an integer
> argument -- and this has something to do with GC? Perhaps it
> reclaims apparently-discarded blocks that are 100 bytes or
> larger, or reclaims all blocks unless there's at least one
> free block (already allocated from the OS, if appropriate,
> but not currently in use) of 100 bytes or more?
>
> You should be more explicit, of course; the proposal is too
> ambiguous. You should also pick a more appropriate name;
> sleep sounds like something for a multitasking OS (allow
> other tasks to run), but this has little to do with GC.
I think you are being a little obtuse with your answer. Valentin's
point is that you can't make a garbage collector mandatory, because code
like he posts will be broken. This also has a major implication for
code libraries, since you can't mix libraries that need GC with those
that must not have GC.
--
Jon Biggar
Floorboard Software
jon@floorboard.com
jon@biggar.org
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Miniussi <miniussi@ilog.fr>
Date: 1999/01/05 Raw View
Scott Johnson wrote:
>
> AllanW@my-dejanews.com wrote:
> >
> > In article <3690FD0E.188D@pratique.fr>,
> > Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > >
> > > Bjarne Stroustrup wrote:
> > >
> > > > There was a lot of talk about a variety of garbage collection schemes.
> > > > I favor optional garbage collection based on conservative collectors.
> > > > I consider such collectors conforming and I proposed that the standard
> > > > explicitly say so.
Could someone tell us what the standard should have actiualy said (eg, what
would have been the meaning of "conforming" in that context ?)
> > > > The explicit statement was voted down, but I still
> > > > see nothing that prohibits conservative garbage collectors for C++.
> > > > That's good because there are free and commercial versions in fairly
> > > > widespread use.
> > >
> > > char * p = malloc (100);
> > > const unsigned long magic = 0x12345678;
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > sleep (100);
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > free (p);
Or even more simple: cout << malloc(100); (then write it done on
a piece of paper etc...)
But
1) that's a deliberate attempt to fool the feature, and I
don't think that C++ is supposed to protect himself against that.
2) you're using reinterpret_cast, which is unfair :-) there
is a specific paragraph on that point in the 3rd edition (which
actually just say that a GC doesn't have to trace pointer stored as
long (which is strange since I think most GC can handle that last
point, they just scan memory)).
3) the behavior of that piece of code is (as you know)
implementation defined anyway.
I think that the only important thing is that, 1) using conservative
(with the meaning "non moving" or/and "maybe some unaccessible memory
won't be reclaimed" ?) you can use normal pointers to store the
adresses, and that, 2) if you don't do anything too tricky, accessible
memory won't be freed, and pointers will remain valid. Now, what we
need is a definition of "conforming", "not too tricky", "conservative"
etc...
> Whether this is actually a problem, or whether the behavior of
> Valentin's example is sufficiently pathological to be ignored, is a
> matter of debate.
>
> More troublesome is this bit of code, which is more "reasonable".
>
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
> putchar (*(--p));
> }
>
> free (p);
> }
I think that kind of situation is handled by some GC (can't remenber
the cost).
A real "problem" would be something like:
char* p = malloc(100);
int offset = 42;
p -= offset;
[...]
p +=offset;
since it's valid, does not use reinterpret_cast, and leave the whole
piece of memory unreferenced.
But I don't know if it can be found in real life (well, it shouldn't).
And there are always way to protect memory from the GC for the patological
situations.
I'm surprised that no one talked about finalization yet, since I think
that a big issue if you want some pseudo standard way to handle GC in
C++.
> Obviously, there are better ways to write this function, and it too is
> offered as an example. OTOH, this sort of code is more likely to be
> encountered in real life; tis not uncommon at all to traverse an array
> without maintaining a pointer to the base of the array. At all points
> in the program, p points to a valid member of the array, or to the "one
> past the end" location...however, if the GC runs in the middle (likely
> as I/O is being done), it may find no valid pointers to the array, and
> trash the array.
>
> Scott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1999/01/05 Raw View
Scott Johnson <sj_nospam@nospam.aracnet.com> writes:
> More troublesome is this bit of code, which is more "reasonable".
>
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
> putchar (*(--p));
> }
>
> free (p);
> }
So a garbage collector should get this "right", i.e. not collect. I
believe this is what "conservative" means in this context: Do not
collect if there are pointers into the block.
Regards,
Martin
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/05 Raw View
Scott Johnson wrote:
>
> Valentin's point is that by engaging in such gratitious
> pointer-swizzling, one can easily fool even a conservative garbage
> collector. If the GC runs during the sleep() interval, it may
> find no valid pointers pointing to the storage allocated in the first
> line, and reclaim such storage. In which case when the pointer
> gets unswizzled, it now is a stray.
>
> Whether this is actually a problem, or whether the behavior of
> Valentin's example is sufficiently pathological to be ignored, is a
> matter of debate.
>
> More troublesome is this bit of code, which is more "reasonable".
>
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
> putchar (*(--p));
> }
>
> free (p);
> }
>
> Obviously, there are better ways to write this function, and it too is
> offered as an example. OTOH, this sort of code is more likely to be
> encountered in real life; tis not uncommon at all to traverse an array
> without maintaining a pointer to the base of the array. At all points
> in the program, p points to a valid member of the array, or to the "one
> past the end" location...however, if the GC runs in the middle (likely
> as I/O is being done), it may find no valid pointers to the array, and
> trash the array.
Actually, this is much easier to deal with than Valentin's example.
Allowing pointers into the middle of objects makes garbage collection
harder, but not impossible.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/05 Raw View
Scott Johnson wrote:
> Valentin's point is that by engaging in such gratitious
> pointer-swizzling, one can easily fool even a conservative garbage
> collector.
Yes
> Whether this is actually a problem, or whether the behavior of
> Valentin's example is sufficiently pathological to be ignored, is a
> matter of debate.
I am not defending my code.
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
> putchar (*(--p));
> }
>
> free (p);
> }
There are no problems with this code. The gc won't reclaim
the storage as there is an unencoded pointer to it.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/05 Raw View
In article <36917DCF.7094@nospam.aracnet.com>,
sj_nospam@nospam.aracnet.com wrote:
>
> AllanW@my-dejanews.com wrote:
> >
> > In article <3690FD0E.188D@pratique.fr>,
> > Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > >
> > > Bjarne Stroustrup wrote:
> > >
> > > > There was a lot of talk about a variety of garbage collection schemes.
> > > > I favor optional garbage collection based on conservative collectors.
> > > > I consider such collectors conforming and I proposed that the standard
> > > > explicitly say so. The explicit statement was voted down, but I still
> > > > see nothing that prohibits conservative garbage collectors for C++.
> > > > That's good because there are free and commercial versions in fairly
> > > > widespread use.
> > >
> > > char * p = malloc (100);
> > > const unsigned long magic = 0x12345678;
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > sleep (100);
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > free (p);
> >
> > Your point, perhaps, is that the C++ standard should include
> > a new library function, called sleep, which accepts an integer
> > argument -- and this has something to do with GC? Perhaps it
> > reclaims apparently-discarded blocks that are 100 bytes or
> > larger, or reclaims all blocks unless there's at least one
> > free block (already allocated from the OS, if appropriate,
> > but not currently in use) of 100 bytes or more?
> >
> > You should be more explicit, of course; the proposal is too
> > ambiguous. You should also pick a more appropriate name;
> > sleep sounds like something for a multitasking OS (allow
> > other tasks to run), but this has little to do with GC.
>
> Valentin's point is that by engaging in such gratitious
> pointer-swizzling, one can easily fool even a conservative garbage
> collector. If the GC runs during the sleep() interval, it may
> find no valid pointers pointing to the storage allocated in the first
> line, and reclaim such storage. In which case when the pointer
> gets unswizzled, it now is a stray.
>
> Whether this is actually a problem, or whether the behavior of
> Valentin's example is sufficiently pathological to be ignored, is a
> matter of debate.
>
> More troublesome is this bit of code, which is more "reasonable".
>
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
> putchar (*(--p));
> }
>
> free (p);
> }
>
> Obviously, there are better ways to write this function, and it too is
> offered as an example. OTOH, this sort of code is more likely to be
> encountered in real life; tis not uncommon at all to traverse an array
> without maintaining a pointer to the base of the array. At all points
> in the program, p points to a valid member of the array, or to the "one
> past the end" location...however, if the GC runs in the middle (likely
> as I/O is being done), it may find no valid pointers to the array, and
> trash the array.
It may find no pointers to the beginning of the array, but it will find
a pointer to the array (or one element past the end of the array). For
all existing garbage collection implementations, this is enough for the
block to be analysed as "reachable".
As it now stands, there are two trouble spots with using third party
garbage collection:
1. Compiler optimizations. Consider the following function:
void
copy( T* dst , T const* src , int n )
{
while ( n -- > 0 )
*dst ++ = *src ++ ;
}
On some machines, the compiler might decide to generate something
similar to the following:
void
copy( T* dst , T const* src , int n )
{
int offset = src - dst ;
while ( n -- > 0 )
{
*dst = *(dst + offset) ;
dst ++ ;
}
}
(Note that *you* cannot do this, since subtracting two pointers that
do not point to the same object is undefined behavior. But the
compiler can, if it knows that the actual behavior is in fact
correct.)
Depending on register allocation, etc., it is possible that there
are no pointers whatsoever remaining to src. And if the copy
constructor of T allocates memory, there is a chance that one of its
allocations fires the garbage collector.
2. Basically what Valentin mentioned: user code which somehow "hides"
the pointer. While xor'ing it with some magic value is unlikely,
copying it into the middle of an array of bytes (unsigned char) at
an unaligned address or writing it to the disk is not unheard of.
The fact that I personally consider such programs broken to begin
with doesn't prevent the fact that people do it, and that at
present, the C++ standard guarantees that it will work.
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/05 Raw View
In article <36917DCF.7094@nospam.aracnet.com>,
sj_nospam@nospam.aracnet.com wrote:
>
> AllanW@my-dejanews.com wrote:
> >
> > In article <3690FD0E.188D@pratique.fr>,
> > Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > >
> > > Bjarne Stroustrup wrote:
> > >
> > > > There was a lot of talk about a variety of garbage collection schemes.
> > > > I favor optional garbage collection based on conservative collectors.
> > > > I consider such collectors conforming and I proposed that the standard
> > > > explicitly say so. The explicit statement was voted down, but I still
> > > > see nothing that prohibits conservative garbage collectors for C++.
> > > > That's good because there are free and commercial versions in fairly
> > > > widespread use.
> > >
> > > char * p = malloc (100);
> > > const unsigned long magic = 0x12345678;
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > sleep (100);
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > free (p);
> >
> > Your point, perhaps, is that the C++ standard should include
> > a new library function, called sleep, which accepts an integer
> > argument -- and this has something to do with GC? Perhaps it
> > reclaims apparently-discarded blocks that are 100 bytes or
> > larger, or reclaims all blocks unless there's at least one
> > free block (already allocated from the OS, if appropriate,
> > but not currently in use) of 100 bytes or more?
> >
> > You should be more explicit, of course; the proposal is too
> > ambiguous. You should also pick a more appropriate name;
> > sleep sounds like something for a multitasking OS (allow
> > other tasks to run), but this has little to do with GC.
>
> Valentin's point is that by engaging in such gratitious
> pointer-swizzling, one can easily fool even a conservative garbage
> collector. If the GC runs during the sleep() interval, it may
> find no valid pointers pointing to the storage allocated in the first
> line, and reclaim such storage. In which case when the pointer
> gets unswizzled, it now is a stray.
>
> Whether this is actually a problem, or whether the behavior of
> Valentin's example is sufficiently pathological to be ignored, is a
> matter of debate.
A good argument to keeping GC optional. Most of us have no use for
such tricks; those who do should not use GC.
> More troublesome is this bit of code, which is more "reasonable".
>
> void reverse_100 (void) {
>
> char * p = malloc (100);
> int i=0;
> for (i = 0; i < 100; ++i) {
> *(p++) = getchar();
> }
> for (i = 99; i >= 0; --i. --p) {
// vv -------- ^^ Don't decrement p twice
> putchar (*(--p));
> }
>
> free (p);
> }
>
> Obviously, there are better ways to write this function, and it too is
> offered as an example. OTOH, this sort of code is more likely to be
> encountered in real life; tis not uncommon at all to traverse an array
> without maintaining a pointer to the base of the array. At all points
> in the program, p points to a valid member of the array, or to the "one
> past the end" location...however, if the GC runs in the middle (likely
> as I/O is being done), it may find no valid pointers to the array, and
> trash the array.
A conservative GC would know that the length of that memory block is
100. Any pointer to any location within the block (and possibly any
pointer to one-past-the-end) would prevent that block from being
released.
Personally, I will consider using GC when someone solves the problem
of how GC-released memory can call destructors first. (AFAIK this
could almost be done now, but not for classes without virtual
functions.) Such a "solution" might be considered an extra burden on
the programmer, but I prefer to consider it additional control. It
means that several paradigms that I've become accustomed to don't
break.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Miniussi <miniussi@ilog.fr>
Date: 1999/01/05 Raw View
AllanW@my-dejanews.com wrote:
>
> A conservative GC would know that the length of that memory block is
> 100. Any pointer to any location within the block (and possibly any
> pointer to one-past-the-end) would prevent that block from being
> released.
It true that a GC can be done in such a way, but it's not related
with the fact that it's a _conservative_ GC (well, conservative can
have a lot of meanings, but I don't know that one).
> Personally, I will consider using GC when someone solves the problem
> of how GC-released memory can call destructors first.
It's called finalization, and it's based on weak pointers (a weak
pointer, from the GC point of view, is a pointer that is not considered
when deciding if memory can be reached, but must be maintained in
some way). It's not new, but there is a cost.
Alain
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Forman <gsez020@compo.bedford.waii.com>
Date: 1999/01/05 Raw View
>>>>> "Miniussi" == Miniussi <miniussi@ilog.fr> writes:
Miniussi> A real "problem" would be something like:
Miniussi> char* p = malloc(100);
Miniussi> int offset = 42;
Miniussi> p -= offset;
Miniussi> [...]
Miniussi> p +=offset;
Miniussi> since it's valid, does not use reinterpret_cast, and
Miniussi> leave the whole piece of memory unreferenced.
Miniussi> But I don't know if it can be found in real life (well,
Miniussi> it shouldn't).
I recall seeing code like this in C to simulate one based indexing.
int * int_vector(size_t s) {
int *p = malloc(s * sizeof(int));
return p ? p - 1 : 0;
}
void free_int_vector(int *p) {
if (p) free (p + 1);
return;
}
--
Pete Forman
Western Geophysical
pete.forman@westgeo.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/05 Raw View
AllanW@my-dejanews.com wrote:
>
>
> A conservative GC would know that the length of that memory block is
> 100. Any pointer to any location within the block (and possibly any
> pointer to one-past-the-end) would prevent that block from being
> released.
In the language of garbage collection, "conservative" means "if it looks
like it might be a pointer, treat it like a pointer." It's conservative
because it is cautious about what it considers garbage. (There's also
what I call an "ultra-conservative" collector, which is even more
cautious: it never treats anything as garbage) That's independent of
whether the garbage collector can deal with pointers into the middle of
an object.
The reason for distinguishing conservative collectors is that they can
work without help from the compiler. They simply scan objects looking
for values that could be pointers (i.e. any value which, treated as a
pointer, points into the heap). Since a large portion of integer values
hold things like 0 and 1, they won't be treated as pointers by a
conservative collector. But when the collector sees a value like
0x120194 it treats it as a pointer, even though it could actually be an
integer. It simply doesn't know. An exact collector needs compiler help,
so that it knows which fields hold pointers.
A consequence of using a conservative collector is that the collector
can't move blocks. That's because the pointer might actually be an int,
and changing its value to reflect the new location of the block would
not be good for the program.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/05 Raw View
In article <3691E273.DC82B7A3@ilog.fr>, Miniussi <miniussi@ilog.fr>
writes
> 2) you're using reinterpret_cast, which is unfair :-) there
>is a specific paragraph on that point in the 3rd edition (which
>actually just say that a GC doesn't have to trace pointer stored as
>long (which is strange since I think most GC can handle that last
>point, they just scan memory)).
But there is a cost in that they have to assume that values that might
be pointers are actually hidden pointers. That means that, for example,
garbage at 'address' 100 will not be collected as long as I have an
appropriate integer variable set to 100 (or any other value between 100
and 100+sizeof(the item at 100).
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/06 Raw View
Miniussi wrote:
>
>
> A real "problem" would be something like:
>
> char* p = malloc(100);
> int offset = 42;
> p -= offset;
> [...]
> p +=offset;
>
> since it's valid,
But it's not. The effect of p -= offset is undefined, because it doesn't
result in a pointer to an element in the original array. Pointer
arithmetic is only defined within an array (including one element past
the end).
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Miniussi <miniussi@ilog.fr>
Date: 1999/01/06 Raw View
Francis Glassborow wrote:
>
> In article <3691E273.DC82B7A3@ilog.fr>, Miniussi <miniussi@ilog.fr>
> writes
> > 2) you're using reinterpret_cast, which is unfair :-) there
> >is a specific paragraph on that point in the 3rd edition (which
> >actually just say that a GC doesn't have to trace pointer stored as
> >long (which is strange since I think most GC can handle that last
> >point, they just scan memory)).
>
> But there is a cost in that they have to assume that values that might
> be pointers are actually hidden pointers. That means that, for example,
> garbage at 'address' 100 will not be collected as long as I have an
> appropriate integer variable set to 100 (or any other value between 100
> and 100+sizeof(the item at 100).
Yes, but that's the way some GC works (and specialy GC for C++): referenced
memory won't be freed, but maybe some unreferenced memory won't be
freed. It's assumed to be acceptable since "usual" integers value
doesn't range in allocated memory adress space. Typicaly, if a GC
for C++ does not involve source processing (and I think most of
them doesn't, you just use a special allocation primitive and link
with the needed library), you don't know the object layout and then
you can't make a distinction betwen "real" and "hidden" pointers, you
just have values.
Alain
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/06 Raw View
AllanW@my-dejanews.com wrote:
>
> In article <3690FD0E.188D@pratique.fr>,
> Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > char * p = malloc (100);
> > const unsigned long magic = 0x12345678;
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > sleep (100);
> > if (sizeof p >= sizeof magic)
> > reinterpret_cast<unsigned long&> (p) ^= magic;
> > free (p);
>
> Your point, perhaps, is that the C++ standard should include
> a new library function, called sleep, which accepts an integer
> argument -- and this has something to do with GC?
???
I was using the well-known, (POSIX ?) sleep function, which
pause teh program for x seconds.
> Perhaps it
> reclaims apparently-discarded blocks that are 100 bytes or
> larger, or reclaims all blocks unless there's at least one
> free block (already allocated from the OS, if appropriate,
> but not currently in use) of 100 bytes or more?
It simply gives a chance to the gc to collect the memory by
giving it more time.
> You should be more explicit, of course; the proposal is too
> ambiguous.
It isn't a proposal ! I was simply giving an example which
would be broken by a gc.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Scott Johnson <sj_nospam@nospam.aracnet.com>
Date: 1999/01/06 Raw View
Martin von Loewis wrote:
>
> Scott Johnson <sj_nospam@nospam.aracnet.com> writes:
>
> > More troublesome is this bit of code, which is more "reasonable".
> >
> > void reverse_100 (void) {
> >
> > char * p = malloc (100);
> > int i=0;
> > for (i = 0; i < 100; ++i) {
> > *(p++) = getchar();
> > }
> > for (i = 99; i >= 0; --i. --p) {
> > putchar (*(--p));
> > }
> >
> > free (p);
> > }
>
> So a garbage collector should get this "right", i.e. not collect. I
> believe this is what "conservative" means in this context: Do not
> collect if there are pointers into the block.
Conservative also means that ANY address located in memory is
interpreted as possbily a pointer. If malloc returns 100 and you
have an int equal to 100 haning around, the storage at 100 will
not be freed.
More aggressive garbage collectors, such as what Java uses, depend on
knowing where all the pointers are.
At any rate, the above snippet briefly references "one past the end",
which is not within the original allocation boundary. A smart
garbage collector might include such "overhead" as part of the
allocation...chances are, in practice, that if anything exists
at p[100], it is the heap data structure for the next allocation.
Scott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/01/06 Raw View
In article <3691E273.DC82B7A3@ilog.fr>, miniussi@ilog.fr says...
[ ... ]
> > > > > There was a lot of talk about a variety of garbage collection schemes.
> > > > > I favor optional garbage collection based on conservative collectors.
> > > > > I consider such collectors conforming and I proposed that the standard
> > > > > explicitly say so.
>
> Could someone tell us what the standard should have actiualy said (eg, what
> would have been the meaning of "conforming" in that context ?)
Without trying to put it into standardese, the basic idea would be to
say that if you made a pointer invisible, unrecognizable, unavailable,
etc., that dereferencing the pointer afterwards would give undefined
results.
IIRC, it doesn't really take anything beyond that. I've used a
conservative collector along with C++ for a few years, and the only
code I've seen break with it was written explicitly to break a GC.
OTOH, if you implement your own specialized memory managers and such a
great deal, it might cause more problems. The usual is NOT to cause
problems with correctness, but simply that in trying to optimize
memory management, you really end up hurting it.
For example, one common strategy in trying to optimize a memory
manager is to use a set of fixed-sizes of blocks that are kept
segregated from each other, with free blocks kept in linked lists.
As it happens, with a typical copying collector, the speed depends
primarily on the amount of memory that's seen as allocated at each
collection cycle. The GC sees the lists of free blocks as being
allocated, so they get copied at every collection cycle, slowing
things considerably. Worse, they often use up a large amount of the
memory being managed by the collector, so they typically cause
collections to happen more frequently, slowing the system still more.
At least in my experience, adding a GC to a program will usually work
best of the program makes little or no attempt at specialized memory
management of its own.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/01/06 Raw View
In article <SHNhd0AhGkk2EwCk@robinton.demon.co.uk>,
francis@robinton.demon.co.uk says...
[ ... ]
> But there is a cost in that they have to assume that values that might
> be pointers are actually hidden pointers. That means that, for example,
> garbage at 'address' 100 will not be collected as long as I have an
> appropriate integer variable set to 100 (or any other value between 100
> and 100+sizeof(the item at 100).
This turns out to (generally) be rather a minor problem. In a typical
situation, you'll have a 32-bit address space and (perhaps) a one or
two megabyte heap being garbage-collected. The GC only cares about
pointers into the heap, not pointers outside the heap, so given 32-bit
integers with all values being equally likely, there's about 2M/4G
chance of any particular value looking like a pointer into the heap.
Note, OTOH, that a pointer to some other area has to be chased in case
it points AT something that contains a pointer into the heap. Even
with this potential multiplication of the number of things that look
like pointers into the heap, things don't end up too terrible as a
rule.
The MUCH greater cost is that you can't compact memory blocks and
patch the pointers to point to the new location of a memory block.
Since you don't know which things are really pointers and which just
look like them, you can't mess with any of them.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/01/06 Raw View
In article <p6qg19q3tb3.fsf@pandora.inst-inf-1.hu-berlin.de>,
loewis@informatik.hu-berlin.de says...
[ ... ]
> > char * p = malloc (100);
> > int i=0;
> > for (i = 0; i < 100; ++i) {
> > *(p++) = getchar();
> > }
> > for (i = 99; i >= 0; --i. --p) {
> > putchar (*(--p));
> > }
> >
> > free (p);
> > }
>
> So a garbage collector should get this "right", i.e. not collect. I
> believe this is what "conservative" means in this context: Do not
> collect if there are pointers into the block.
This isn't a problem regardless of whether you're looking at a
"conservative" collector or not.
In this context, "conservative" means two things.
A "normal" collector (e.g. in a Smalltalk, LISP or Java system)
"knows" which things are pointers and which aren't. When determining
objects that are still "live" it only follows things that are
pointers. When it's doing a collection, it puts all the blocks that
are still in use next to each other, patching the pointers to point to
the new location of the block.
A conservative collector doesn't know which things are pointers and
which aren't, so it has to assume that anything with the right bit
pattern MIGHT be a pointer into a block. However, it can never assume
that it really IS a pointer, so it can't move the block and patch the
pointer to the new location because what it's looking at MIGHT not be
a pointer at all.
Hans Boehm has done testing indicating that neither of these is as big
a problem as might initially appear to be the case. My own empirical
testing bears this out...
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/01/06 Raw View
In article <36932352.5A87A308@ilog.fr>, Miniussi <miniussi@ilog.fr> wrote:
>Francis Glassborow wrote:
>> But there is a cost in that they have to assume that values that might
>> be pointers are actually hidden pointers. That means that, for example,
>> garbage at 'address' 100 will not be collected as long as I have an
>> appropriate integer variable set to 100 (or any other value between 100
>> and 100+sizeof(the item at 100).
>
>Yes, but that's the way some GC works (and specialy GC for C++): referenced
>memory won't be freed, but maybe some unreferenced memory won't be
>freed.
That's precisely what makes these collectors "conservative". They assume
that any word in memory that could be a pointer is one, and won't free what
it points to.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/06 Raw View
In article <3691A1C2.DC5A1415@floorboard.com>,
Jonathan Biggar <jon@floorboard.com> wrote:
>
> AllanW@my-dejanews.com wrote:
> > > char * p = malloc (100);
> > > const unsigned long magic = 0x12345678;
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > sleep (100);
> > > if (sizeof p >= sizeof magic)
> > > reinterpret_cast<unsigned long&> (p) ^= magic;
> > > free (p);
> >
> > Your point, perhaps, is that the C++ standard should include
> > a new library function, called sleep, which accepts an integer
> > argument -- and this has something to do with GC? Perhaps it
[snip]
>
> I think you are being a little obtuse with your answer. Valentin's
> point is that you can't make a garbage collector mandatory, because code
> like he posts will be broken. This also has a major implication for
> code libraries, since you can't mix libraries that need GC with those
> that must not have GC.
Yes, you're right, and I apologize to Valentin.
I've seen this argument before, though. Most of them, like Valentin's,
are contrived. The point is always that this *could* happen in real
code, although only rarely does anyone own up to working on code like
this, and I've never seen anyone state that they did it themselves.
But let's say that you have a bona-fide exception on your hands. Your
application allocates memory and then mungs the pointer in some way,
un-munging it before use. It wasn't written for the sole purpose of
proving what a bad idea GC is, but for some other purpose where it
really accomplished something. (Maybe you've found a way to
"compress" the pointers, so that an array of N*sizeof(void*) bytes
can somehow store 2*N pointers.) In any case, GC would break your
code. Is that a good reason to NOT bring GC into C++?
Not unless the techniques used are in some way common. After all,
lots of C++ features have broken a few C (or even older C++) programs
in the past. Consider //-style comments, which break code like this:
i = j //* Comment */k
-1;
Here, the old C rules make this equivalent to i=j/k-1, while the C++
rules make it equivalent to i=j-1. Both expressions are valid, and in
compilers I've used, there isn't even a warning about the changed
behavior. A less contrived example:
i = j //*Comment*/
-1;
This used to be equivalent to i=j/-1, now it's equivalent to i=j-1.
We didn't let a few broken programs deprive us of this useful
syntax, because we expected that only a very few programs would
break due to this feature. I believe the same thing could be
said of GC.
- - -
That having been said, I still believe that GC, if implemented, should
be optional. Like most other things, making it automatic means giving
up a certain degree of control. Specifically, I feel uneasy not knowing
if a destructor will ever be called. It makes me much less likely to
depend on "automatic clean-up" of certain non-memory resources.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/07 Raw View
Miniussi wrote:
>
> Scott Johnson wrote:
> >
> > AllanW@my-dejanews.com wrote:
> > >
> > > In article <3690FD0E.188D@pratique.fr>,
> > > Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > > >
> > > > Bjarne Stroustrup wrote:
> > > >
> > > > > There was a lot of talk about a variety of garbage collection schemes.
> > > > > I favor optional garbage collection based on conservative collectors.
> > > > > I consider such collectors conforming and I proposed that the standard
> > > > > explicitly say so.
>
> Could someone tell us what the standard should have actiualy said (eg, what
> would have been the meaning of "conforming" in that context ?)
Yes:
If a block of memory (something obtained with operator new or
malloc or realloc) is made invisible, then every pointer value
inside or one past the end the memory block has an invalid value.
A block of memory is said to be invisible if no visible pointer in
the program points inside or one past the end this block of memory.
A pointer is said to be visible if it isn't part of an visible
block of memory.
(hum hum... we have a circularity here (at least it's a positive
one))
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/07 Raw View
In article <3691E273.DC82B7A3@ilog.fr>,
Miniussi <miniussi@ilog.fr> wrote:
> A real "problem" would be something like:
>
> char* p = malloc(100);
> int offset = 42;
> p -= offset;
> [...]
> p +=offset;
>
> since it's valid, does not use reinterpret_cast, and leave the whole
> piece of memory unreferenced.
It's not valid. If you write it, it is undefined behavior.
On the other hand, as I pointed out in another posting, the compiler is
free to generate things like this internally, which means that a
conservative garbage collector might not work with some specific
compiler.
I suspect that the big problem with garbage collection is going to be in
distributed systems. I personally think it bad design, but it wouldn't
surprise me if some distributed systems maintained the only pointer to
an object in a map on another machine. Which the garbage collector
can't see. In fact, the main reason we didn't use garbage collection on
my last project is that we had no guarantee that none of the third party
software was doing this. (We were particularly worried about CORBA.)
> But I don't know if it can be found in real life (well, it shouldn't).
> And there are always way to protect memory from the GC for the patological
> situations.
>
> I'm surprised that no one talked about finalization yet, since I think
> that a big issue if you want some pseudo standard way to handle GC in
> C++.
Perhaps because finalization is a red herring. Instead of calling
"delete p", you call "p->finalize()". Big deal. In fact, IMHO,
finalization should usually be separate from memory deallocation -- what
happens if the transaction fails, and you have to roll back?
On the other hand, the necessity of managing memory causes finalization
to propagate automatically -- the destructors always call delete on the
memory they own. I've been working entirely in Java lately, and one of
the things I've noticed is that people don't propagate finalization; in
fact, the Swing library doesn't propagate it. The result is that owned
objects don't know that they have logically ceased to exist, so they
don't deregister themselves from where ever they are registered, so the
registry doesn't free its pointer to them, and you get a memory leak.
(I've seen more memory leaks in two months of Java than in 15 years of
C/C++. So much for silver bullets.)
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/07 Raw View
In article <tuk8z1bk2c.fsf@compo.bedford.waii.com>,
Pete Forman <gsez020@compo.bedford.waii.com> wrote:
> I recall seeing code like this in C to simulate one based indexing.
>
> int * int_vector(size_t s) {
> int *p = malloc(s * sizeof(int));
> return p ? p - 1 : 0;
> }
>
> void free_int_vector(int *p) {
> if (p) free (p + 1);
> return;
> }
I've seen lots of wrong code, too. The above is simply undefined
behavior, according to both the C and the C++ standards.
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: thp@vdo.ucr.edu (Tom Payne)
Date: 1999/01/07 Raw View
Valentin Bonnard (bonnardv@pratique.fr) wrote:
: AllanW@my-dejanews.com wrote:
: >
: > In article <3690FD0E.188D@pratique.fr>,
: > Valentin Bonnard <bonnardv@pratique.fr> wrote:
: > > char * p = malloc (100);
: > > const unsigned long magic = 0x12345678;
: > > if (sizeof p >= sizeof magic)
: > > reinterpret_cast<unsigned long&> (p) ^= magic;
: > > sleep (100);
: > > if (sizeof p >= sizeof magic)
: > > reinterpret_cast<unsigned long&> (p) ^= magic;
: > > free (p);
: > You should be more explicit, of course; the proposal is too
: > ambiguous.
: It isn't a proposal ! I was simply giving an example which
: would be broken by a gc.
Is this example "conforming"?
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/07 Raw View
In article <MPG.10fcbbdb408e07f49897d0@news.rmi.net>,
jcoffin@taeus.com (Jerry Coffin) wrote:
> The MUCH greater cost is that you can't compact memory blocks and
> patch the pointers to point to the new location of a memory block.
> Since you don't know which things are really pointers and which just
> look like them, you can't mess with any of them.
That isn't really a cost. We're talking about either including
conservative GC or excluding it. Either way, we don't compact memory
blocks in C++.
The fact that some other language has more support for GC, which
allows it to transparently compact memory blocks, isn't really
relevant unless you propose doing the same thing in C++. But this
would require compiler support. For some reason that escapes me,
nobody wants to consider GC that requires compiler support.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/07 Raw View
Scott Johnson wrote:
>
>
> More aggressive garbage collectors, such as what Java uses, depend on
> knowing where all the pointers are.
The Java language definition does not prohibit the use of a conservative
collector. Some implementations use a conservative collector, some
don't.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/07 Raw View
In article <3692A152.F266628@acm.org>,
Pete Becker <petebecker@acm.org> wrote:
>
> Miniussi wrote:
> >
> >
> > A real "problem" would be something like:
> >
> > char* p = malloc(100);
> > int offset = 42;
> > p -= offset;
> > [...]
> > p +=offset;
> >
> > since it's valid,
>
> But it's not. The effect of p -= offset is undefined, because it doesn't
> result in a pointer to an element in the original array. Pointer
> arithmetic is only defined within an array (including one element past
> the end).
True.
But I have come up with a VERY realistic case where even conservative
Garbage Collection would interfere with the program. It's from a real
programming technique that I have used on Microsoft Windows. Since
it's real instead of contrived, even the simplified explanation is
going to be longer than everything I've read so far. But please bear
with me.
We have a Windows application, say a simple 4-function calculator.
We wish to allow the user to have multiple windows open at the same
time. These windows should NOT interact -- for instance, pressing
"Clear" on one calculator should not affect the others. Since we
can have multiple instances of the calculator, we create a class
named Calculator which encapsulates all of the various state
variables.
When the user presses the "Clear" button (by any means: tabbing
to it and pressing SPACE, or pressing ALT+C, or by clicking with
the mouse), the Windows OS sends our application a message. Like
all Windows messages, it has four parameters:
The HWND, a unique Handle to Window, which identifies which
window had the CLEAR key pressed.
The message id, which in this case is WM_COMMAND. This means
that the user has requested a Windows "Command", in this
case the command is "Clear."
Two more integers whose meaning depends on the message id.
In this case, one of the parameters will be the ID of the
"Clear" button.
It's easy to parse this information and recognize it as a Clear
command. The hard part is to find the address of the Calculator
instance associated with this window. The "obvious" way goes
something like this: Create a global array (or something
similar) to associate window handles with Calculators.
std::map<HWND,Calculator*> CalcList;
Calculator*FindCalc(HWND h) {
return map[h];
}
I've used basically this approach many times successfully. (I started
doing this before Iheard of the STL; I used a global array of
structures, where the structure had the HWND and a Calculator*.
Then I did a linear search.)
But what happens if our pointy-haired boss hires an OO consultant to
"fix" our code? He looks at the global variables and starts thumping
his "Big Anal Book of OO Principles." "No global variables," he shouts...
So we make a small change. Windows allows us to create windows that
have "Extra Data" associated with them. We ask for sizeof(Calculator*)
extra bytes for each Calculator window, and set them to the address of
the Calculator* for the associated window. Then we change FindCalc:
Calculator*FindCalc(HWND h) {
// GetWindowLong(h, 0) returns the 32-bit value as a long.
return (Calculator*)GetWindowLong(h,0);
}
When we've finished this, we look at our code and admit, rather
reluctantly, that the code is a bit better this way. The code is
better encapsulated, and there's no global variable to maintain.
There used to be a gradual slowdown as more and more windows
were created, but now the application seems much faster.
But this new code would also break Garbage Collection, if we used
it. Until we receive a message, the pointer to the calculator is
no longer in ANY variable in the program. It's in the "Windows
Extra Data", which is someplace in the Windows OS. It's not even
in our address space!
For this application to run properly, we MUST be able to turn off
Garbage Collection. (Or, we can change the app to adjust to GC,
say by maintaining a linked list of Calculators which we will
never use, or by allocating the Calculator in a special No-GC mode.
But either of these are intrusive.)
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: zalman@netcom.com (Zalman Stern)
Date: 1999/01/07 Raw View
AllanW@my-dejanews.com wrote:
[Stashing a pointer using SetWindowLong in Win32 might break conservative
GC.]
I'm pretty sure real packages for doing conservative GC in C++ handle
problems like this by allowing you to extend the logic that enumerates the
collection roots. E.g. whip down the list of windows and do a GetWindowLong
and assume whatever is returned is a pointer. (One will have to do likewise
for thread local storage in many environments, including Win32 with certain
programming paradigms.) One can also explicitly register root pointers and
register blocks of storage that should not be scanned (e.g. image buffers).
The bottom line is that programmer fashion is against GC. So far as I can
tell, most of the problems are solveable. Especially if you are willing to
spend as much effort solving them as many projects do on "old fashioned"
memory allocation issues such as fragmentation, dangling pointer bugs,
storage leaks, etc.
There is no free lunch. But it helps to know what you're actually paying
for the one you're eating now and what the alternatives are.
-Z-
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: deepblack@geocities.com (Luis Coelho)
Date: 1999/01/07 Raw View
On 7 Jan 1999 05:21:47 GMT, AllanW@my-dejanews.com uttered the
following words:
<snip>
>But I have come up with a VERY realistic case where even conservative
>Garbage Collection would interfere with the program. It's from a real
<windows example snipped>
One possibily I once read of is designing a doubly-linked list
using only one pointer per node which maintains both the next and
the previous pointer XOR'd together, thus saving one pointer per
node.
Here's what I mean (I know this is terrible code, but it shows
what I mean in little space):
<code>
template <typename T>
class List
{
struct Node
{
Node* previous_and_next; // !!
T* data;
};
Node* head;
Node* tail;
public:
void print() const;
// ...
};
// Now to walk the list
template<typename T>
void List<T>::print() const
{
Node* iter = head;
while (iter != tail)
{
cout << T;
iter = iter.previous_and_next ^ iter;
}
}
</code>
Regards,
Luis Coelho.
C++ Programming Language, 3rd Ed. by B. Stroustrup. My exercise answers at:
http://www.geocities.com/SiliconValley/Way/3972/index.html
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/07 Raw View
> Specifically, I feel uneasy not knowing
> if a destructor will ever be called.
As no one has mentionned it yet, I want to cite BS opinion
on this: gc models infinite memory in a finite computer:
you never free memory, but as you have infinite memory, you
don't get a bad_alloc (well, you can get a bad_alloc, but
latter than w/o gc). When you never delete things, dtors
are never called, so a gc shouldn't try to call dtors of
collected objects.
And it's simplier to implement... :)
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/07 Raw View
Tom Payne wrote:
>
> Valentin Bonnard (bonnardv@pratique.fr) wrote:
> : AllanW@my-dejanews.com wrote:
> : >
> : > In article <3690FD0E.188D@pratique.fr>,
> : > Valentin Bonnard <bonnardv@pratique.fr> wrote:
>
> : > > char * p = malloc (100);
> : > > const unsigned long magic = 0x12345678;
> : > > if (sizeof p >= sizeof magic)
> : > > reinterpret_cast<unsigned long&> (p) ^= magic;
> : > > sleep (100);
> : > > if (sizeof p >= sizeof magic)
> : > > reinterpret_cast<unsigned long&> (p) ^= magic;
> : > > free (p);
>
> : > You should be more explicit, of course; the proposal is too
> : > ambiguous.
>
> : It isn't a proposal ! I was simply giving an example which
> : would be broken by a gc.
>
> Is this example "conforming"?
What about replacing sleep(100) with
try
{
for(int i=0; i<10000; ++i) new int[10000];
}
catch(bad_alloc)
{
cerr << "Hey, you forgot to collect! ;-)";
}
This is conforming and will certainly trigger GC ;-)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/01/07 Raw View
In article <7710of$jce$1@nnrp1.dejanews.com>, <AllanW@my-dejanews.com> wrote:
>So we make a small change. Windows allows us to create windows that
>have "Extra Data" associated with them.
> ...
>But this new code would also break Garbage Collection, if we used
>it. Until we receive a message, the pointer to the calculator is
>no longer in ANY variable in the program. It's in the "Windows
>Extra Data", which is someplace in the Windows OS. It's not even
>in our address space!
This method isn't even specific to the MS-Windows API. It is also possible
to do exactly the same thing in X-Windows. In that case the pointer may
even be on a *different* *machine*. Good luck getting GC to find it *there*.
[And I do not think we are quite in the territory of undefined behavior here,
since the conversions involved are allowed as long as the pointer actually
dereferenced is of the original type].
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ivo Welch <ivo.welch@anderson.ucla.edu>
Date: 1998/12/22 Raw View
I read the dejanews archives of this group; a couple of years back there was
some discussion about the ANSI ISO committee looking into a GC scheme. What
happened to it? Is there hope? (A newgc operator would probably take half
the wind out of Java's sails, and make a lot of messy libraries a log nicer.)
[Anyone know about gcc plans in this respect?]
Sincerely,
Ivo welch
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/12/22 Raw View
In article <3680169B.8110DC67@anderson.ucla.edu>, Ivo Welch
<ivo.welch@anderson.ucla.edu> writes
>
>
>I read the dejanews archives of this group; a couple of years back there was
>some discussion about the ANSI ISO committee looking into a GC scheme. What
>happened to it? Is there hope? (A newgc operator would probably take half
>the wind out of Java's sails, and make a lot of messy libraries a log nicer.)
Certainly there is hope but not for a long time (five years before there
would even be a working paper for C++200X to put it into)
That does not prevent implementors from experimenting with extensions,
and such experimentation would build a knowledge base on which
specification could be based.
The reason why no work was done on it a couple of years ago was that we
were already trying to ship a standard and I doubt that many would have
thanked us for another delay of a year or more.
Note that there are fundamental differences in the C++ and Java models
as applied to variables that effect this area. All instances of Java
user-defined types are anonymous, Java variables are just identifiers
that can be re(bound) to these anonymous instances. In C++ we have
named instances and references to instances that cannot be rebound.
These differences are not cosmetic but fundamental to the way the two
languages work.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Luca Arzeni" <arzenil@tin.it>
Date: 1999/01/01 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> scritto nell'articolo
<8RgKIvAGuCg2EwHK@robinton.demon.co.uk>...
>
> In article <3680169B.8110DC67@anderson.ucla.edu>, Ivo Welch
> <ivo.welch@anderson.ucla.edu> writes
> >
> >
> >I read the dejanews archives of this group; a couple of years back there
was
> >some discussion about the ANSI ISO committee looking into a GC scheme.
What
> >happened to it? Is there hope? (A newgc operator would probably take
half
> >the wind out of Java's sails, and make a lot of messy libraries a log
nicer.)
I've still not tested it, but the strong pointers seems to be an
interesting idea. I suggest you to take a look at www.resource.com, by
Milewski.
I hope to have not bothered you.
Bye, Luca
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul Sorensen" <psorensen@wedgewood.net>
Date: 1999/01/03 Raw View
Was this something that was "switched on" by some directive - I don't think
it's something that you'd want in all cases.
Paul Sorensen
Ivo Welch <ivo.welch@anderson.ucla.edu> wrote in message
news:3680169B.8110DC67@anderson.ucla.edu...
>
>I read the dejanews archives of this group; a couple of years back there
was
>some discussion about the ANSI ISO committee looking into a GC scheme.
What
>happened to it? Is there hope? (A newgc operator would probably take half
>the wind out of Java's sails, and make a lot of messy libraries a log
nicer.)
>
>[Anyone know about gcc plans in this respect?]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: bs@research.att.com (Bjarne Stroustrup)
Date: 1999/01/04 Raw View
"Paul Sorensen" <psorensen@wedgewood.net> writes:
> Was this something that was "switched on" by some directive - I don't
> think it's something that you'd want in all cases.
>
> Paul Sorensen
> Ivo Welch <ivo.welch@anderson.ucla.edu> wrote in message
> news:3680169B.8110DC67@anderson.ucla.edu...
> >
> >I read the dejanews archives of this group; a couple of years back
> > there was some discussion about the ANSI ISO committee looking into
> > a GC scheme. What happened to it? Is there hope? (A newgc operator
> > would probably take half the wind out of Java's sails, and make a lot
> > of messy libraries a log nicer.)
> >
> >[Anyone know about gcc plans in this respect?]
There was a lot of talk about a variety of garbage collection schemes.
I favor optional garbage collection based on conservative collectors.
I consider such collectors conforming and I proposed that the standard
explicitly say so. The explicit statement was voted down, but I still
see nothing that prohibits conservative garbage collectors for C++.
That's good because there are free and commercial versions in fairly
widespread use.
For details from a language point of view see
Stroustrup: The Design and Evolution of C++
Addison-Wesley, 1994
Stroustrup: The C++ Programming Language (3rd Edition)
Addison-Wesley, 1997
- Bjarne
Bjarne Stroustrup - http://www.research.att.com/~bs
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]