Topic: NULL "this" pointers
Author: James Kuyper <kuyper@wizard.net>
Date: Mon, 30 Oct 2000 19:31:47 GMT Raw View
"Balog Pal (mh)" wrote:
>
> James Kuyper wrote in message <39E90E68.647BA845@wizard.net>...
>
> >> That is pretty much misleading. When you want to dereference a pointer,
> it
> >> is loaded into the 'address' registers. That may lead to some trap.
> >> When you want to use them for other purposes, like compare with 0, the
> >> pointer value is loaded into a data register. That will not cause a trap.
> >
> >Yes. That's one way to do it. However, that's not the only way to do it,
> >nor is it the only way that it is actually done.
>
...
> check. If the registers are just for addressing purposes, they can't be used
> for calculation.
It is the latter case I was considering.
...
> the machine code. If it is actually a register, loading it with value on a
> protecrted system is likely to have immediate check, and trap if the value
> is inappropriate.
That's precisely the behavior I'm talking about.
> >Sure - and what do they do when those validity checks fail? At the OS
> >level there's not much that can be done but terminate the offending
> >program.
>
> Generally it choses from two possibilities: replace the value with a null
> selector or kills the process. I think the first one is more common on
And those option are allowed only because the behavior from accessing a
deleted pointer is undefined.
...
> >The OS can do it as "gently" as possible, but the OS doesn't
> >know anything about the design of your program, so it can seldom do
> >anything significantly gentler than the equivalent of calling abort().
>
> Sure thing. Acting outside the task's potential address space is an
> unrecoverable problem. But it's unlikely to occour in process. The address
Do you mean "unlikely to occur in practice"? If not, I'm not sure how to
interpret that sentence.
> space is created when the process start, and stays.
In that case, you're talking about a different kind of architecture. The
type I've heard of that's relevant to this problem has portions of the
address space that become valid only as a consequence of successful
memory allocation, and which can become invalid as a consequence of
deallocation, and registers which trap (usually fatally) on load of an
invalid address.
> >> even if a trap happens, it does not ususally go to the air, but the OS
> >> catches it ang can analyse the situation.
> >
> >And what should it do with the analysis?
>
> Every system has its logic, on what to do on traps. load pages, rearrange
> memory, substitute values, retry. Or kill the process. It may be even
> dependent on type of process, protection level, rights of the actual user.
Most of those are not useful things to do in response to a load of an
invalid pointer. Of the ones you've listed, "substitute" and "kill" are
the only useful ones. Both of those choices can trigger consequences
that are allowed in a C++ program only because the behavior of accessing
a deleted pointer value is undefined.
> All those things are pretty far from C++ and C++'s memory manager. I
> personally doubt the C++ free store manager ever returns a poitner with
> selector which selector will be ever revoked from being valid until the task
> finishes. (And if it does, that was the thing I referred to as OS sadism.
> ;-)
I would consider such memory-hogging behavior by the C++ free store
manager to be extremely unfriendly in a multi-tasking environment (which
is the kind of environment I do all of my work in). I've heard that many
C++ implementations are indeed memory hogs; could this be the reason
why?
> >> If what you say is correct, and code like:
> >>
> >> X * p1 = new X;
> >> X * const p2 = p1;
> >> X * const p3 = p1;
> >> delete p1;
> >> if (p2 == p3) cout <<"equal";
> >>
> >> is illegal, and allowed to compile trapping code I say that's a serious
> >> problem with the language.
> >
> >Well it is illegal. It's the value of a pointer that you're not
> >permitted access after it's been deleted, not the pointer itself.
>
> I can't quite decipher that. Accessing the pointer's value and the pointer
> itself means the same to me. What is exactly permittes and what is not? What
> can I do with the 'pointer itself' then?
The same value is stored in p1, p2, and p3. Any use of that value after
the delete is prohibited, no matter which of the three locations that
value is retrieved from. The only thing you can legally due with any of
those pointers is to store a new, valid, value in it.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: kanze@gabi-soft.de
Date: Mon, 30 Oct 2000 19:55:05 GMT Raw View
"Balog Pal (mh)" <pasa@lib.hu> writes:
|> James Kuyper wrote in message <39E90E68.647BA845@wizard.net>...
|> >> That is pretty much misleading. When you want to dereference a
|> >> pointer, it is loaded into the 'address' registers. That may lead
|> >> to some trap. When you want to use them for other purposes, like
|> >> compare with 0, the pointer value is loaded into a data
|> >> register. That will not cause a trap.
|> >Yes. That's one way to do it. However, that's not the only way to
|> >do it, nor is it the only way that it is actually done.
|> I asked for actual counterexamples, seen none by this time.
Intel 80386, using 48 bit pointers. The simplest way of pushing a
pointer onto the stack loads the pointer with a single instruction into
a segment register/normal register pair, then pushing each of the
registers. Loading an invalid segment into a segment register traps.
You can avoid this by using other instruction sequences. Since loading
a segment register is expensive, most compilers today will use these
other sequences. But all of them are physically longer than the
simplest sequence, and when the 80386 first appeared, memory was still
considered an expensive component, to be economized. (I can remember
when we first programmed on the 80386. We used to avoid manipulating
pointers precisely because the compiler *always* loaded segment and
offset, and the segment load was so expensive. IIRC, about the only
thing you could do with a pointer without loading the segment was ++ or
--.) (The segment 0 was mapped to a write protected page of all zeros,
so that null pointers would work.)
|> Certainly everything is possible, but the logic is on my side.
What logic? The C committee decided to formulate the standard in a way
that would not impose excessive (space) overhead on one of the most
widespread processor of the time. That seems like a reasonable decision
to me. (The C committee actually went to great lengths to allow
efficient implementations on some exceptionally exotic material.)
|> The
|> processor has either single or multipurpose registers. If the later,
|> the problem does not apply, you can load arbitrary value, it can't
|> undergo address validity check. If the registers are just for
|> addressing purposes, they can't be used for calculation.
|> >I'm describing architectures I've heard about, mostly on this
|> >newsgroup, not ones I've actually used (or maybe I have - I never
|> >try to access the value of deleted pointers, so I wouldn't notice
|> >the difference). I'm afraid I'll have to ask those who've knowingly
|> >used such systems to comment on how common they are.
Well, the 80386 wasn't exactly rare, although I think most compilers for
it only used 32 bit pointers and a flat address space.
|> I'm really curious. Most systems I know have a composite scheme for
|> addressing.
Really. The current Intel hardware supports a composite scheme, but
neither Windows nor Linux use it. IBM mainframes have as sort of funny
addressing scheme as well. But everything else I know today uses flat,
linear addressing at the process level.
[...]
|> >Sure - and what do they do when those validity checks fail? At the O=
S
|> >level there's not much that can be done but terminate the offending
|> >program.
|> Generally it choses from two possibilities: replace the value with a
|> null selector or kills the process. I think the first one is more
|> common on architectures with register arrays and alike stuff.
I've *never* see an OS which would change an address on an address
fault.
[...]
|> Sure thing. Acting outside the task's potential address space is an
|> unrecoverable problem. But it's unlikely to occour in process. The
|> address space is created when the process start, and stays.
And how do malloc/operator new work? Every OS I've worked on has had
some way of increasing the process address space. Most also have
provisions for reducing it.
[...]
|> All those things are pretty far from C++ and C++'s memory manager. I
|> personally doubt the C++ free store manager ever returns a poitner
|> with selector which selector will be ever revoked from being valid
|> until the task finishes. (And if it does, that was the thing I
|> referred to as OS sadism. ;-)
I've not verified the actual details, but free'ed memory under Windows
NT can occasionally make its way back to the OS. With the results that
any pointers to that memory will cause a general protection fault if
used.
|> >> If what you say is correct, and code like:
|> >>
|> >> X * p1 =3D new X;
|> >> X * const p2 =3D p1;
|> >> X * const p3 =3D p1;
|> >> delete p1;
|> >> if (p2 =3D=3D p3) cout <<"equal";
|> >> is illegal, and allowed to compile trapping code I say that's a
|> >> serious problem with the language.
|> >Well it is illegal. It's the value of a pointer that you're not
|> >permitted access after it's been deleted, not the pointer itself.
|> I can't quite decipher that. Accessing the pointer's value and the
|> pointer itself means the same to me. What is exactly permittes and
|> what is not? What can I do with the 'pointer itself' then?
I can't decipher the response either, but the code definitly invokes
undefined behavior in the comparison. As mentioned above, I have
actually used a processor/compiler combination where it would cause a
hardware interrupt, at least with certain compiler options.
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Balog Pal (mh)" <pasa@lib.hu>
Date: 2000/10/25 Raw View
James Kuyper wrote in message <39E90E68.647BA845@wizard.net>...
>> That is pretty much misleading. When you want to dereference a pointer,
it
>> is loaded into the 'address' registers. That may lead to some trap.
>> When you want to use them for other purposes, like compare with 0, the
>> pointer value is loaded into a data register. That will not cause a trap.
>
>Yes. That's one way to do it. However, that's not the only way to do it,
>nor is it the only way that it is actually done.
I asked for actual counterexamples, seen none by this time. Certainly
everything is possible, but the logic is on my side. The processor has
either single or multipurpose registers. If the later, the problem does not
apply, you can load arbitrary value, it can't undergo address validity
check. If the registers are just for addressing purposes, they can't be used
for calculation.
>I'm describing architectures I've heard about, mostly on this newsgroup,
>not ones I've actually used (or maybe I have - I never try to access the
>value of deleted pointers, so I wouldn't notice the difference). I'm
>afraid I'll have to ask those who've knowingly used such systems to
>comment on how common they are.
I'm really curious. Most systems I know have a composite scheme for
addressing. There are special registers tied to memory addressing (they have
different names, like selector, address space identifier, etc), and some
indexing register (or a plenty of them) are used to calculate offset into
the segment (even if it is not called one). The selector may be completely
invisible on the user level, or being part of the process state, or a bit in
the machine code. If it is actually a register, loading it with value on a
protecrted system is likely to have immediate check, and trap if the value
is inappropriate.
Other checks then happen only at actual addressing, to see if the pointed
area is within limits, and type of access is allowed.
>Sure - and what do they do when those validity checks fail? At the OS
>level there's not much that can be done but terminate the offending
>program.
Generally it choses from two possibilities: replace the value with a null
selector or kills the process. I think the first one is more common on
architectures with register arrays and alike stuff. That way checks are
simply deferred, if the process actually try to access memory without
loading a legal value, another trap happens. If not, everything is good and
transparent. (It might also be a strategy, that the offending value is
replaced with the task's only valid selector. )
>The OS can do it as "gently" as possible, but the OS doesn't
>know anything about the design of your program, so it can seldom do
>anything significantly gentler than the equivalent of calling abort().
Sure thing. Acting outside the task's potential address space is an
unrecoverable problem. But it's unlikely to occour in process. The address
space is created when the process start, and stays.
>> even if a trap happens, it does not ususally go to the air, but the OS
>> catches it ang can analyse the situation.
>
>And what should it do with the analysis?
Every system has its logic, on what to do on traps. load pages, rearrange
memory, substitute values, retry. Or kill the process. It may be even
dependent on type of process, protection level, rights of the actual user.
All those things are pretty far from C++ and C++'s memory manager. I
personally doubt the C++ free store manager ever returns a poitner with
selector which selector will be ever revoked from being valid until the task
finishes. (And if it does, that was the thing I referred to as OS sadism.
;-)
>> If what you say is correct, and code like:
>>
>> X * p1 = new X;
>> X * const p2 = p1;
>> X * const p3 = p1;
>> delete p1;
>> if (p2 == p3) cout <<"equal";
>>
>> is illegal, and allowed to compile trapping code I say that's a serious
>> problem with the language.
>
>Well it is illegal. It's the value of a pointer that you're not
>permitted access after it's been deleted, not the pointer itself.
I can't quite decipher that. Accessing the pointer's value and the pointer
itself means the same to me. What is exactly permittes and what is not? What
can I do with the 'pointer itself' then?
Paul
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 26 Oct 2000 14:35:59 GMT Raw View
In article <39f6f538@andromeda.datanet.hu>, Balog Pal (mh) <pasa@lib.hu>
writes
>If the registers are just for addressing purposes, they can't be used
>for calculation.
Why not? Unless you mean for computation of things other than addresses.
Francis Glassborow 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Balog Pal (mh)" <pasa@lib.hu>
Date: Thu, 26 Oct 2000 16:02:29 GMT Raw View
Francis Glassborow wrote in message ...
>>If the registers are just for addressing purposes, they can't be used
>>for calculation.
>
>Why not? Unless you mean for computation of things other than addresses.
If the registers are general purpose (you can use them for math and
addressing likewise), they can't trap on loading value that is illegal as a
pointer, but good as a number so the whole discussed problem can't apply. If
they're not, you have to live with limitations.
Suppose a quite common processor, an Intel 386+. How do you compare two
pointers?
Easy to ask, not so easy to answer. ;-)
To remain sane let's completely forget page translation, and assume the
linear address is equal with the memory address. (That aspect should be
transparent anyway).
Now, to have an address we have a selector and ann offset. For addressing
purposes the offset can be calculates in interesting ways, but when stored
in a pointer it's just a plain 16 or 32 bit value, we forget anything else.
Now, in flat, or unisegment memory models we have the easiest case. The
program is supposed to have a single memory area allocated, and selectors
covering the whol of that memory in unique way is loaded into all the
segment registers. Their actual value is not interesting, and all you gave
to compare is the offset part, that is stored in that word or dword. wow.
(that covers win32/application level and old dos tiny model. If we limit our
examinations to data pointers, then small and medium models are also covered
in dos&win16).
In the other cases we can't avoid dealing with the selector part. The first
thing to state is you can't do anything with the selector part while it's
loaded in the segment register. You have to pass the value into a data
register. Then, we must make some design assumptations, on what 'pointers
are equal' means in the first place. ;-) when their selector and offset is
equal, or extend the meaning to cases when those differ, but they target the
same memory spot.
If we decide the latter, we have to obtain the segment base address, and
calculate the linear address as the processor would. In real mode that meand
just multiplying the selector value by 0x10, in protected mode the base
address must be fetched from the appropriate descriptor table. Oops, it's
quite unlikely we can just reach it. Maybe some system call can help. Or we
have a limited option to ask the system whether our pair of selectors have
the same base (some systems allow creating aliases descriptors pointing the
same memory with different rights, etc.) Or without that at least the
'level' bits must be masked off that does not have part in selection of the
descriptor table and slot, and compare just the rest. (That is, even if the
processor could do a cmp fs, gs the result would not be reliable, as 0xc7
in one abd 0xc4 in the other should be treated as equal.)
Life is not easy wrt pointer math. One may call Intel some weird animal, but
it isn't, addressing is pretty similar (compared with its native/protected
mode) on most advanced processors. And that particular problem exists in the
deep for most languages and applications, so the systems tend to grant
useful limitations on the chaos, like uniselector, or distinct-selector
models, at least for the application level.
Also, to my observations the processors with traps are likely the more
advanced ones tend to have multipurpose registers. While the limited ones
that limit ALU operations to the accumulator, or have specialised
memory-addressing(only) registers rarely do not trap.
I still wait someone to show a system that ill-behaves on my earlier
example.
Paul
======================================= MODERATOR'S COMMENT:
This thread is no longer related to the Standard and has become quite platform-specific. Followups elsewhere, please.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/10/15 Raw View
In article <1eig9u9.6w6hd0i5br2kN%jthill@telus.net>, Jim Hill
<jthill@telus.net> writes
>It seems to me that quite a bit of effort went into ensuring magic like
>that is permitted. See for instance the discussion of object lifetime,
>particularly 3.8p5 and its example -- that "should" work just as clearly
>as yours, at least to a pointer's-just-a-bitbag pair of eyes like mine,
>but it's defined not to.
Allowed, but not required.
>
>The only way I can make sense of that is to posit a pointer-tagging
>system such as I described above. Note that all definitions of stale
>pointer semantics in 3.8, including access to exactly the same type at
>exactly the same address, terminate when the storage is released.
>Therefore I believe your example is not csc++-legal.
I think you are mistaken, else user written operator new/delete pairs
can be in awful trouble. The point of these is that I get to provide the
precise semantics of allocation/deallocation.
Francis Glassborow 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/10/16 Raw View
In article <39e7995c@andromeda.datanet.hu>, Balog Pal <pasa@lib.hu>
writes
>That is pretty much misleading. When you want to dereference a pointer, it
>is loaded into the 'address' registers. That may lead to some trap.
>When you want to use them for other purposes, like compare with 0, the
>pointer value is loaded into a data register. That will not cause a trap.
Oh, you mean that if I write:
cout << * x_ptr;
if(x_ptr != y_ptr) cout <<" and " << *y_ptr <<endl;
the compiler is required to shift my pointers back and forth between
registers should there be distinct address and data registers? Surely
not.
Francis Glassborow 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: jthill@telus.net (Jim Hill)
Date: 2000/10/16 Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> <jthill@telus.net> writes
> >[...]that is permitted.[...]
> Allowed, but not required.
Of course. But from what follows, I wonder if you meant "not required"
to refer to something other than enforcement of deallocated-storage
semantics? I think I missed your point here.
> >The only way I can make sense of that is to posit a pointer-tagging
> >system such as I described above. Note that all definitions of stale
> >pointer semantics in 3.8, including access to exactly the same type at
> >exactly the same address, terminate when the storage is released.
> >Therefore I believe your example is not csc++-legal.
>
> I think you are mistaken, else user written operator new/delete pairs
> can be in awful trouble.
How so? It isn't the new/delete pairs, it's the code that uses the
address of a deallocated object.
> The point of these is that I get to provide the
> precise semantics of allocation/deallocation.
You're flatly contradicting the standard:
> Any allocation and/or deallocation functions defined in a C++ program
> shall conform to the semantics specified in 3.7.3.1 and 3.7.3.2.
which includes invalidating all pointers into the deallocated storage.
Jim
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Balog Pal" <pasa@lib.hu>
Date: 2000/10/17 Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote
> >That is pretty much misleading. When you want to dereference a pointer,
it
> >is loaded into the 'address' registers. That may lead to some trap.
> >When you want to use them for other purposes, like compare with 0, the
> >pointer value is loaded into a data register. That will not cause a trap.
>
> Oh, you mean that if I write:
>
> cout << * x_ptr;
> if(x_ptr != y_ptr) cout <<" and " << *y_ptr <<endl;
>
> the compiler is required to shift my pointers back and forth between
> registers should there be distinct address and data registers? Surely
> not.
I think where address and data registers are truly distinct it has not much
options, as you can't do math with values in address registers even
comparision. But that is just speculation on my part. All systems I recall I
used lately are safe to use recently deleted pointer values (but not random
garbage!) for anything but dereference.
Certainly nothing forbids the existance of such a system, but on those rare
birds I'd likely be happy to have at least a compiler switch for a safe
mode. (Like sun compilers have that unaligned switch).
Can someone point an actual system on which the discussed problem is a
problem? I could check it out in detail at least.
Paul
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Trevor L. Jackson, III" <fullmoon@aspi.net>
Date: 2000/10/20 Raw View
James Kuyper wrote:
> John G Harris wrote:
> >
> > In article <Zb+jq4AdO445EwfQ@ntlworld.com>, Francis Glassborow
> > <francis.glassborow@ntlworld.com> writes
> > >In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
> > ><john@nospam.demon.co.uk> writes
> > >>Surely it's still permitted to display the value of a pointer. If so,
> > >>then automatically nulling pointers will alter the semantics of some
> > >>conforming programs.
> > >
> > >No, accessing an invalid pointer value has undefined behaviour.
> >
> > I meant display as in
> > cout << p;
> > not as in dereferencing. Is that undefined (apart from format)?
>
> Yes - accessing the pointer for any purpose is undefined; it doesn't
> matter whether or not you derefence it. Here's a simple model that
> explains the reason for this, which describes a fair number of real
> systems:
>
> At the hardware level, a pointer does not point directly at a piece of
> physical memory. Instead, part of the pointer is an index into a table
> of memory blocks, the remainder contains an offset into the block. The
> system keeps track of which blocks are currently in use, and immediately
> terminates any process that attempts to load a pointer register with a
> value that indicates a currently unused block. std::free() calls OS
> functions that, among other things, might release one of those blocks,
> rendering any pointer that refers to that block (NOT just the pointer
> that was free()'d) to be unloadable. The argument passing convention for
> this platform calls for pointers to be passed by placing them into a
> pointer register.
>
> Net result: "cout<<p" tries to call the appropriate operator overload
> function, attempting to load the value of p into a pointer register.
> This results in immediate termination of your program.
>
> This is a deliberate safety measure, not some weird kind of OS sadism.
> It's intended to minimize the damage that could be done by code written
> by people who are careless about pointers.
This conclusion is not well founded. An equivalent level of protection is
available without all of the lethal recessive implications of premature
pointer validation. Checking the pointer's validity when it is dereferenced
imposes no safety/security risks (but might impact performance). However,
checking the pointer's validity when it is dereferenced eliminates whole
classes of exception artifacts. Promising to check pointer validity on
loading (and ignoring pointer validity on use) _does_ create safety/security
risks.
For example, a virtual address passed as an argument in a register is often
push on the stack to free the register. On exit from the called function one
typically pops the saved value so that the caller is not burdened with
reloading it. Yet premature pointer validation makes restoring registers
dangerous. If the called function releases the target of the pointer the
pointer will become invalid. Other address register may already be loaded
with dangling references to the target. While the intention of premature
pointer validation may be to minimize damage created by careless pointer
handling, the truth is that it encourages a false sense of security in re
pointer validation and tends to increase carelessness and decrease
reliability of systems built upon it.
This is not to say that there aren't silly machine architectures in
existence. It is to say, paraphrasing Lincoln, that calling something a
safety measure does not make it one.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Balog Pal" <pasa@lib.hu>
Date: 2000/10/14 Raw View
"James Kuyper" <kuyper@wizard.net> wrote in message
> Yes - accessing the pointer for any purpose is undefined; it doesn't
> matter whether or not you derefence it. Here's a simple model that
> explains the reason for this, which describes a fair number of real
> systems:
>
> At the hardware level, a pointer does not point directly at a piece of
> physical memory. Instead, part of the pointer is an index into a table
> of memory blocks, the remainder contains an offset into the block. The
> system keeps track of which blocks are currently in use, and immediately
> terminates any process that attempts to load a pointer register with a
> value that indicates a currently unused block.
That is pretty much misleading. When you want to dereference a pointer, it
is loaded into the 'address' registers. That may lead to some trap.
When you want to use them for other purposes, like compare with 0, the
pointer value is loaded into a data register. That will not cause a trap.
> std::free() calls OS
> functions that, among other things, might release one of those blocks,
> rendering any pointer that refers to that block (NOT just the pointer
> that was free()'d) to be unloadable. The argument passing convention for
> this platform calls for pointers to be passed by placing them into a
> pointer register.
You can hardly call that a widely used system of passing arguments IMHO.
> Net result: "cout<<p" tries to call the appropriate operator overload
> function, attempting to load the value of p into a pointer register.
> This results in immediate termination of your program.
> This is a deliberate safety measure, not some weird kind of OS sadism.
> It's intended to minimize the damage that could be done by code written
> by people who are careless about pointers.
It much more resembles sadism (OS and compiled working together in perfect
team). When a pointer is just a piece of data from the program's point of
view it shouldnot be loaded into an addressing register in the first place.
And safe architectures have instructions that check pointer values for
validity to read, write, or do some operations just setting flags. Also,
even if a trap happens, it does not ususally go to the air, but the OS
catches it ang can analyse the situation.
If what you say is correct, and code like:
X * p1 = new X;
X * const p2 = p1;
X * const p3 = p1;
delete p1;
if (p2 == p3) cout <<"equal";
is illegal, and allowed to compile trapping code I say that's a serious
problem with the language.
Paul
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: jthill@telus.net (Jim Hill)
Date: 2000/10/14 Raw View
Joerg Barfurth <joerg.barfurth@attglobal.net> wrote:
> But in any case, nullifying would need to be restricted to the case
> where the standard deallocation function is used, because otherwise
> delete needn't produce an invalid pointer value.
I disagree. 3.7.3p3:
> Any allocation and/or deallocation functions defined in a C++ program
> shall conform to the semantics specified in 3.7.3.1 and 3.7.3.2.
3.7.3.2p4 (particularly the double-quoted part):
> If the argument given to a deallocation function in the standard library
> is a pointer that is not the null pointer value (4.10), the deallocation
> function shall deallocate the storage referenced by the pointer,
>> rendering invalid all pointers referring to any part of the
>> deallocated storage.
> The effect of using an invalid pointer value (including passing
> it to a deallocation function) is undefined.
There's nothing preventing an implementation from using compiler magic
on new/delete to e.g. put "object ids" in new'd pointers and invalidate
them on return from delete.
It seems to me that quite a bit of effort went into ensuring magic like
that is permitted. See for instance the discussion of object lifetime,
particularly 3.8p5 and its example -- that "should" work just as clearly
as yours, at least to a pointer's-just-a-bitbag pair of eyes like mine,
but it's defined not to.
The only way I can make sense of that is to posit a pointer-tagging
system such as I described above. Note that all definitions of stale
pointer semantics in 3.8, including access to exactly the same type at
exactly the same address, terminate when the storage is released.
Therefore I believe your example is not csc++-legal.
Jim
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: James Kuyper <kuyper@wizard.net>
Date: Sun, 15 Oct 2000 03:25:37 GMT Raw View
Balog Pal wrote:
>
> "James Kuyper" <kuyper@wizard.net> wrote in message
>
> > Yes - accessing the pointer for any purpose is undefined; it doesn't
> > matter whether or not you derefence it. Here's a simple model that
> > explains the reason for this, which describes a fair number of real
> > systems:
> >
> > At the hardware level, a pointer does not point directly at a piece of
> > physical memory. Instead, part of the pointer is an index into a table
> > of memory blocks, the remainder contains an offset into the block. The
> > system keeps track of which blocks are currently in use, and immediately
> > terminates any process that attempts to load a pointer register with a
> > value that indicates a currently unused block.
>
> That is pretty much misleading. When you want to dereference a pointer, it
> is loaded into the 'address' registers. That may lead to some trap.
> When you want to use them for other purposes, like compare with 0, the
> pointer value is loaded into a data register. That will not cause a trap.
Yes. That's one way to do it. However, that's not the only way to do it,
nor is it the only way that it is actually done.
> > std::free() calls OS
> > functions that, among other things, might release one of those blocks,
> > rendering any pointer that refers to that block (NOT just the pointer
> > that was free()'d) to be unloadable. The argument passing convention for
> > this platform calls for pointers to be passed by placing them into a
> > pointer register.
>
> You can hardly call that a widely used system of passing arguments IMHO.
I'm describing architectures I've heard about, mostly on this newsgroup,
not ones I've actually used (or maybe I have - I never try to access the
value of deleted pointers, so I wouldn't notice the difference). I'm
afraid I'll have to ask those who've knowingly used such systems to
comment on how common they are.
> > Net result: "cout<<p" tries to call the appropriate operator overload
> > function, attempting to load the value of p into a pointer register.
> > This results in immediate termination of your program.
>
> > This is a deliberate safety measure, not some weird kind of OS sadism.
> > It's intended to minimize the damage that could be done by code written
> > by people who are careless about pointers.
>
> It much more resembles sadism (OS and compiled working together in perfect
> team). When a pointer is just a piece of data from the program's point of
> view it shouldnot be loaded into an addressing register in the first place.
> And safe architectures have instructions that check pointer values for
> validity to read, write, or do some operations just setting flags. Also,
Sure - and what do they do when those validity checks fail? At the OS
level there's not much that can be done but terminate the offending
program. The OS can do it as "gently" as possible, but the OS doesn't
know anything about the design of your program, so it can seldom do
anything significantly gentler than the equivalent of calling abort(). A
C compiler for such a platform could detect the problem in advance, and
do the equivalent of exit(), which is a little bit gentler. A C++
compiler for such a platform could throw an exception, which is even
gentler, but will often have essentially the same effect.
> even if a trap happens, it does not ususally go to the air, but the OS
> catches it ang can analyse the situation.
And what should it do with the analysis?
> If what you say is correct, and code like:
>
> X * p1 = new X;
> X * const p2 = p1;
> X * const p3 = p1;
> delete p1;
> if (p2 == p3) cout <<"equal";
>
> is illegal, and allowed to compile trapping code I say that's a serious
> problem with the language.
Well it is illegal. It's the value of a pointer that you're not
permitted access after it's been deleted, not the pointer itself. Both
p2 and p3 have copies of that value, and therefore cannot be safely
accessed.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: John G Harris <john@nospam.demon.co.uk>
Date: 2000/10/12 Raw View
In article <Zb+jq4AdO445EwfQ@ntlworld.com>, Francis Glassborow
<francis.glassborow@ntlworld.com> writes
>In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
><john@nospam.demon.co.uk> writes
>>Surely it's still permitted to display the value of a pointer. If so,
>>then automatically nulling pointers will alter the semantics of some
>>conforming programs.
>
>No, accessing an invalid pointer value has undefined behaviour.
I meant display as in
cout << p;
not as in dereferencing. Is that undefined (apart from format)?
John
--
John Harris
mailto:john@jgharris.demon.co.uk
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: James Kuyper <kuyper@wizard.net>
Date: Fri, 13 Oct 2000 05:00:11 GMT Raw View
John G Harris wrote:
>
> In article <Zb+jq4AdO445EwfQ@ntlworld.com>, Francis Glassborow
> <francis.glassborow@ntlworld.com> writes
> >In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
> ><john@nospam.demon.co.uk> writes
> >>Surely it's still permitted to display the value of a pointer. If so,
> >>then automatically nulling pointers will alter the semantics of some
> >>conforming programs.
> >
> >No, accessing an invalid pointer value has undefined behaviour.
>
> I meant display as in
> cout << p;
> not as in dereferencing. Is that undefined (apart from format)?
Yes - accessing the pointer for any purpose is undefined; it doesn't
matter whether or not you derefence it. Here's a simple model that
explains the reason for this, which describes a fair number of real
systems:
At the hardware level, a pointer does not point directly at a piece of
physical memory. Instead, part of the pointer is an index into a table
of memory blocks, the remainder contains an offset into the block. The
system keeps track of which blocks are currently in use, and immediately
terminates any process that attempts to load a pointer register with a
value that indicates a currently unused block. std::free() calls OS
functions that, among other things, might release one of those blocks,
rendering any pointer that refers to that block (NOT just the pointer
that was free()'d) to be unloadable. The argument passing convention for
this platform calls for pointers to be passed by placing them into a
pointer register.
Net result: "cout<<p" tries to call the appropriate operator overload
function, attempting to load the value of p into a pointer register.
This results in immediate termination of your program.
This is a deliberate safety measure, not some weird kind of OS sadism.
It's intended to minimize the damage that could be done by code written
by people who are careless about pointers.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "David Thompson" <david.thompson1@worldnet.att.net>
Date: Fri, 13 Oct 2000 05:02:10 GMT Raw View
Peter Dimov <pdimov@mmltd.net> wrote :
....
> The real problem with the proposal is, as Francis Glassborow pointed
> out, "do you want delete to operate on values, on variables, or
> something in between?" To take advantage of the fact that delete sets
> pointers to 0 you have to remember whether you delete'd the pointer
> variable or its value. This is a source of bugs.
<SARCASM=HIGH>
Oh, but there's a wonderful mnemonic for this:
delete p; // p is also set to 0 (if a modifiable lvalue)
delete p - 0; // "take away" the setting to 0, leave unchanged
This fits right in with = 0 for pure virtuals.
</>
--
- David.Thompson 1 now at worldnet.att.net
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: joerg.barfurth@attglobal.net (Joerg Barfurth)
Date: 2000/10/13 Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
> <john@nospam.demon.co.uk> writes
> >Surely it's still permitted to display the value of a pointer. If so,
> >then automatically nulling pointers will alter the semantics of some
> >conforming programs.
>=20
> No, accessing an invalid pointer value has undefined behaviour.
But in any case, nullifying would need to be restricted to the case
where the standard deallocation function is used, because otherwise
delete needn't produce an invalid pointer value.
#include <cstdlib>
#include <new>
unsigned char bytes[sizeof(int)];
void* alloc =3D 0;
void* operator new(std::size_t sz)
{
if (sz =3D=3D sizeof bytes && alloc =3D=3D 0)
return alloc =3D bytes;
if (void* p =3D std::malloc(sz))
return p;
throw std::bad_alloc();
}
void operator delete(void* p)
{
if (p =3D=3D alloc)
alloc =3D 0;
else
std::free(p);
}
void to_null_or_not(int*& x)
{
x =3D new int(42);
delete x;
}
int main()
{
int* p =3D 0;
to_null_or_not(p);
=20
return * new (p) int (0);
}
I think that currently this program (in particular the last line of
main) is legal ...
Regards, J=F6rg
--=20
J=F6rg Barfurth joerg.barfurth@attglobal.net
-------------- using std::disclaimer; -----------------------------
Download: StarOffice 5.2 at http://www.sun.com/staroffice
Participate: OpenOffice now at http://www.OpenOffice.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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/10/13 Raw View
John G Harris <john@nospam.demon.co.uk> writes:
>Francis Glassborow <francis.glassborow@ntlworld.com> writes
>>In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
>><john@nospam.demon.co.uk> writes
>>>Surely it's still permitted to display the value of a pointer. If so,
>>>then automatically nulling pointers will alter the semantics of some
>>>conforming programs.
>>
>>No, accessing an invalid pointer value has undefined behaviour.
>
>I meant display as in
> cout << p;
>not as in dereferencing. Is that undefined (apart from format)?
Yes, that is undefined. Simply accessing an invalid pointer value
results in undefined behaviour, even if you don't dereference it.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: John G Harris <john@nospam.demon.co.uk>
Date: 2000/10/10 Raw View
In article <8rnist$f1b$1@plutonium.compulink.co.uk>,
brangdon@cix.compulink.co.uk writes
<snip>
>The proposal does not effect the semantics of currently correct programs.
>This is a definite virtue. It will break no existing code that is not
>already broken.
<snip>
Surely it's still permitted to display the value of a pointer. If so,
then automatically nulling pointers will alter the semantics of some
conforming programs.
John
--
John Harris
mailto:john@jgharris.demon.co.uk
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/10/10 Raw View
In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
<john@nospam.demon.co.uk> writes
>Surely it's still permitted to display the value of a pointer. If so,
>then automatically nulling pointers will alter the semantics of some
>conforming programs.
No, accessing an invalid pointer value has undefined behaviour.
Francis Glassborow 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Mark Williams <markw65@my-deja.com>
Date: 2000/10/11 Raw View
In article <Zb+jq4AdO445EwfQ@ntlworld.com>,
Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> In article <T5zQxVA4K345EwsI@jgharris.demon.co.uk>, John G Harris
> <john@nospam.demon.co.uk> writes
> >Surely it's still permitted to display the value of a pointer. If so,
> >then automatically nulling pointers will alter the semantics of some
> >conforming programs.
>
> No, accessing an invalid pointer value has undefined behaviour.
But you can always copy its constituent bytes into an array of
unsigned char, and compare it with a previous copy. Or print out the
decimal values of those chars. It amounts to the same thing.
-------------
Mark Williams
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/10/08 Raw View
David R Tribble <david@tribble.com> writes:
| michael <serrano@ozemail.com.au> writes:
| >| The proposition "std behaviour is a shame" should be backed up by an
| >| argument.
|
| Gabriel Dos Reis wrote:
| > Yes, I asked for such argument but didn't get any convincing one.
|
| I gave one.
Then I should have missed it :-)
| [1] Mandate that 'delete' should automatically invalidate its pointer
| operand (by setting it to null).
|
| This would plug a hole in the language, which currently allows
| dangling pointers to be created without any warnings.
As I already pointed out, that doesn't cure the problem. What about
computed pointer values? Your proposal doesn't handle
struct list_node_base {
list_node_base* next;
void* data;
};
template<typename T> struct list_node : list_node_base {
void deallocate_data()
{ delete ((T*) data); }
};
Furthermore, it was shown how the language as is already provides the
programmer with the necessary and sufficient abstraction tools to get
your nullifying deletion:
template<typename T>
void my_fancy_nullifying_delete(T*&);
If using that fonction makes your programs less buggy, then you may
turn it into a library and lobby for it. But at any rate, I don't
think a language change is necessary.
| [2] A special exception would be mandated for deleting const pointers.
What about rvalues?
| A warning would be issued that a dangling pointer is being created,
| but the delete would still be allowed to occur.
I would hat it to have noise about well sound program constructs.
| [3] The compiler would be free to optimize away the pointer
| invalidation if it can determine that it is unnecssary (such as
| deleting a pointer that is about to go out of scope).
But then, why don't you request your compiler vendor to implement your
proposal and switch to current rules only when it can determine it is
safe to do so? Doing that would constitute an existing practice ;-)
But, so far I didn't see any argument backing up the fact the current
rule is a shame.
| Some people pointed out that deleting a null pointer was benign
| under C++ rules. They pointed out that perfectly valid programs
| depended on this behavior. So it made sense to them (logical
| symmetry) that 'delete' should nullify its pointer.
|
| One of the arguments against my proposal was that it does not provide
| any added benefit. "If you want a deleted pointer to be null, just
| set it to null." I counter with the question, then why do dangling
| pointers occur if C++ is so safe already?
I would ask: how do dangling pointers occur in your program?
The real matter isn't about C++ being safe or not. It is about
(mis)usage of abstraction tools.
| Another question I asked was, why *not* let the compiler nullify the
| pointer? Half the responses were concerned with efficiency; see [3].
| I am willing to accept what tiny overhead there may be to let the
| compiler set deleted pointers to null if it saves me from having to
| do it after every delete.
|
| The other half said it didn't go far enough because it didn't nullify
| every pointer to the object; but surely if you've got multiple
| pointers to an object, that is your problem and not the compiler's.
The other half you didn't consider was the example I gave above.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: James Dennett <james@evtechnology.com>
Date: 2000/10/08 Raw View
Mark Williams wrote:
> In article <39DD2CEB.79BFD445@wizard.net>,
> James Kuyper <kuyper@wizard.net> wrote:
> > Peter Dimov wrote:
> > > It is not my intention to reopen the discussion, but the answer to
> this
> > > particular concern is simple:
> > >
> > > {
> > > T * tmp = p;
> > > delete tmp;
> > > }
> >
> > That doesn't do any good. The only reason for not wanting pointers
> > nulled is to avoid the time wasted doing so; there's no legal use for
> > the unnulled value. Not only does this approach not avoid that waste,
> it
> > compounds it by wasting space creating and initializing a temporary
> copy
> > of the pointer.
>
> But if your compiler cant optimize away both the copy, and the nullify
> in *that* situation, you have far bigger performance problems to worry
> about than whether or not delete nulls its argument.
Double but: if your compiler considers it a good idea to null deleted
pointers and is smart enough to optimise away tmp, it might also be
"smart enough" to waste its time nulling p anyway. It's allowed to
by the Standard :)
A compiler can already legally null deleted pointers, or it can provide
a switch to determine whether this is done, or it can just produce fast
code. I see no need for a change to the Standard. A simple template
can already achieve this effect inside Standard C++.
Maybe people would be better campaigning for either (a) code which
wraps raw pointers in resource management classes, which use short
methods so that deleted pointers aren't accessible anyway, or (b)
compilers which are better at spotting obvious use of invalid pointers.
Probably a good lint-like tool will do this already.
-- James Dennett <jdennett@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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: brangdon@cix.compulink.co.uk
Date: 2000/10/08 Raw View
davidjl@gol.com (David J. Littleboy) wrote (abridged):
> Anyway, since it's incorrect to use a pointer that's been deleted,
> regardless of whether it's been set to null, you're proposing a
> language feature that only affects incorrect programs. I may be
> wrong but, isn't this radically different from anything else in
> the language?
The proposal turns some currently incorrect programs into correct ones.
That is quite normal. It is what many proposals do.
The proposal does not effect the semantics of currently correct programs.
This is a definite virtue. It will break no existing code that is not
already broken.
So I don't think it is "radically different" or unfriendly. It is a
conservative, well-behaved proposal.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/10/09 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
| "Gabriel Dos Reis" <gdr@merlin.codesourcery.com> wrote in message
| news:m38zs7f6f4.fsf@merlin.codesourcery.com...
| > Stealing identifiers from the user namespace and turn them into
| > keywords have the potential to break existing codes.
|
| I was thinking that the standard already reserves identifies containing two
| underscores or starting with an underscore followed by a capital letter.
| Therefore I think no standard-compliant user code can contain
| __uninitialized or _Uninitialized.
I get it. Thanks
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: David R Tribble <david@tribble.com>
Date: 2000/10/04 Raw View
michael <serrano@ozemail.com.au> writes:
>| The proposition "std behaviour is a shame" should be backed up by an
>| argument.
Gabriel Dos Reis wrote:
> Yes, I asked for such argument but didn't get any convincing one.
I gave one.
[1] Mandate that 'delete' should automatically invalidate its pointer
operand (by setting it to null).
This would plug a hole in the language, which currently allows
dangling pointers to be created without any warnings.
[2] A special exception would be mandated for deleting const pointers.
A warning would be issued that a dangling pointer is being created,
but the delete would still be allowed to occur.
[3] The compiler would be free to optimize away the pointer
invalidation if it can determine that it is unnecssary (such as
deleting a pointer that is about to go out of scope).
Some people pointed out that deleting a null pointer was benign
under C++ rules. They pointed out that perfectly valid programs
depended on this behavior. So it made sense to them (logical
symmetry) that 'delete' should nullify its pointer.
One of the arguments against my proposal was that it does not provide
any added benefit. "If you want a deleted pointer to be null, just
set it to null." I counter with the question, then why do dangling
pointers occur if C++ is so safe already?
Another question I asked was, why *not* let the compiler nullify the
pointer? Half the responses were concerned with efficiency; see [3].
I am willing to accept what tiny overhead there may be to let the
compiler set deleted pointers to null if it saves me from having to
do it after every delete.
The other half said it didn't go far enough because it didn't nullify
every pointer to the object; but surely if you've got multiple
pointers to an object, that is your problem and not the compiler's.
Others stated that setting pointers to null created a false sense
of security. I'm not sure how else you can know that a pointer no
longer points to anything other than setting it to null.
Others suggested setting the pointer to an invalid value other than
null, to cause program crashes later on if the pointer was
subsequently used. This is very little different than setting it
to null, which is *the* invalid pointer value, and requires the added
expense of checking for two values to validate the pointer.
michael:
>| I don't think anyone proposes "std behavior should be changed"
I am.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Mark Williams <markw65@my-deja.com>
Date: 2000/10/04 Raw View
In article <8qift1$ggd$1@plutonium.compulink.co.uk>,
brangdon@cix.compulink.co.uk wrote:
> Am I right in thinking that after "delete p", accessing p itself is an
> error? Eg:
>
> char *p = new char[2];
> char *p2 = p;
> delete p;
> assert( p == p2 ); // Undefined behaviour?
There was a similar thread on comp.std.c recently about whether free
could do the same thing. After *much* heated debate, the final
conclusion appeared to be that no, it could not, because the bytes of
the pointer can be read into an array of unsigned char before and after
the free, and those bytes could be compared.
In other words, the value of p when treated as a pointer
become undefined (eg it may become a trap value), but the value of the
bytes that make up p may not be changed.
However, ISTR the ARM explicily allowing delete to NULLify its argument
if it was a modifiable lvalue... I dont recall if that made it into the
standard or not.
-------------
Mark Williams
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/10/05 Raw View
In article <39DB61F7.949E4622@tribble.com>, David R Tribble
<david@tribble.com> writes
>>| I don't think anyone proposes "std behavior should be changed"
>
>I am.
OK, but as long as you understand what you are proposing is a change to
the type of the 'argument' used in the delete expression. Currently
something like:
delete reinterpret_cast<mytype *> 1234;
is, AFAIK, valid, even if unusual. I only use it to highlight that
currently a pointer value is used, whereas your proposal requires that a
pointer variable is used.
Francis Glassborow 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "David J. Littleboy" <davidjl@gol.com>
Date: 2000/10/05 Raw View
"David R Tribble" <david@tribble.com> wrote:
>
> One of the arguments against my proposal was that it does not provide
> any added benefit. "If you want a deleted pointer to be null, just
> set it to null." I counter with the question, then why do dangling
> pointers occur if C++ is so safe already?
My best guess would be that dangling pointer problems are far more often due
to an object referenced by multiple pointers being deleted than reuse of a
deleted pointer. If only because the later can be caught in a code review.
> Another question I asked was, why *not* let the compiler nullify the
> pointer? Half the responses were concerned with efficiency; see [3].
> I am willing to accept what tiny overhead there may be to let the
> compiler set deleted pointers to null if it saves me from having to
> do it after every delete.
>
> The other half said it didn't go far enough because it didn't nullify
> every pointer to the object; but surely if you've got multiple
> pointers to an object, that is your problem and not the compiler's.
>
> Others stated that setting pointers to null created a false sense
> of security. I'm not sure how else you can know that a pointer no
> longer points to anything other than setting it to null.
How about a code review? Uses of deleted pointers (other than globals) are
local to the function that deletes them. That means that the only cases the
proposal handles are the ones that are lexically visible, and it fails to
deal with the hard problems. That's why the "false sense of security"
criticism is directly related to it's not going far enough. It doesn't fix
the problem yet claims to do so.
Anyway, since it's incorrect to use a pointer that's been deleted,
regardless of whether it's been set to null, you're proposing a language
feature that only affects incorrect programs. I may be wrong but, isn't this
radically different from anything else in the language?
David J. Littleboy
Tokyo, Japan
PS: Dave Harris wrote elsewhere "Admittedly, we'd have to write
non-conforming code to take advantage of it, which probably takes the point
away.", which is the point that I'm making above.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/10/05 Raw View
David R Tribble <david@tribble.com> writes:
>[1] Mandate that 'delete' should automatically invalidate its pointer
>operand (by setting it to null).
>
>This would plug a hole in the language, which currently allows
>dangling pointers to be created without any warnings.
Even with this change, you could still create dangling pointers
without any warnings.
Foo *p = new Foo;
Foo *q = p;
delete p, p = NULL;
// q is now dangling
So it wouldn't plug any holes. At best it might make the hole
a little narrower.
>One of the arguments against my proposal was that it does not provide
>any added benefit. "If you want a deleted pointer to be null, just
>set it to null." I counter with the question, then why do dangling
>pointers occur
Because setting deleted pointers to null doesn't prevent dangling
pointers (among other reasons).
>if C++ is so safe already?
No-one said C++ was safe ;-)
>Another question I asked was, why *not* let the compiler nullify the
>pointer?
Actually I don't think anyone would mind too much if compilers were
*allowed* to nullify such pointers. The question is whether we should
*require* that behaviour.
>Half the responses were concerned with efficiency; see [3].
>I am willing to accept what tiny overhead there may be to let the
>compiler set deleted pointers to null if it saves me from having to
>do it after every delete.
>
>The other half said it didn't go far enough because it didn't nullify
>every pointer to the object; but surely if you've got multiple
>pointers to an object, that is your problem and not the compiler's.
By the same kind of argument, surely if you are relying an invariant
that requires setting deleted pointers to null, that is your problem
and not the compiler's.
>Others stated that setting pointers to null created a false sense
>of security. I'm not sure how else you can know that a pointer no
>longer points to anything other than setting it to null.
In most cases, pointers will be deleted only when they are about to go
out of scope, or some other program invariant will ensure that a
pointer which has been deleted will never be accessed.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: John G Harris <john@nospam.demon.co.uk>
Date: 2000/10/05 Raw View
In article <39DB61F7.949E4622@tribble.com>, David R Tribble
<david@tribble.com> writes
<snip>
>[1] Mandate that 'delete' should automatically invalidate its pointer
>operand (by setting it to null).
>
>This would plug a hole in the language, which currently allows
>dangling pointers to be created without any warnings.
<snip>
>Another question I asked was, why *not* let the compiler nullify the
>pointer? Half the responses were concerned with efficiency; see [3].
>I am willing to accept what tiny overhead there may be to let the
>compiler set deleted pointers to null if it saves me from having to
>do it after every delete.
>
>The other half said it didn't go far enough because it didn't nullify
>every pointer to the object; but surely if you've got multiple
>pointers to an object, that is your problem and not the compiler's.
<snip>
And a third half asked "what about those who don't want pointers
nulled?" Your proposed change to the language must include a means to do
this, as a language feature not a compiler option.
John
--
John Harris
mailto:john@jgharris.demon.co.uk
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Peter Dimov" <pdimov@mmltd.net>
Date: 2000/10/05 Raw View
"John G Harris" <john@nospam.demon.co.uk> wrote in message
news:Hl8VGKA6ZL35Ew35@jgharris.demon.co.uk...
>
> And a third half asked "what about those who don't want pointers
> nulled?" Your proposed change to the language must include a means to
do
> this, as a language feature not a compiler option.
It is not my intention to reopen the discussion, but the answer to this
particular concern is simple:
{
T * tmp = p;
delete tmp;
}
--
Peter Dimov
Multi Media Ltd.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: James Kuyper <kuyper@wizard.net>
Date: 2000/10/06 Raw View
Peter Dimov wrote:
>
> "John G Harris" <john@nospam.demon.co.uk> wrote in message
> news:Hl8VGKA6ZL35Ew35@jgharris.demon.co.uk...
> >
> > And a third half asked "what about those who don't want pointers
> > nulled?" Your proposed change to the language must include a means to
> do
> > this, as a language feature not a compiler option.
>
> It is not my intention to reopen the discussion, but the answer to this
> particular concern is simple:
>
> {
> T * tmp = p;
> delete tmp;
> }
That doesn't do any good. The only reason for not wanting pointers
nulled is to avoid the time wasted doing so; there's no legal use for
the unnulled value. Not only does this approach not avoid that waste, it
compounds it by wasting space creating and initializing a temporary copy
of the pointer.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Mark Williams <markw65@my-deja.com>
Date: 2000/10/06 Raw View
In article <39DD2CEB.79BFD445@wizard.net>,
James Kuyper <kuyper@wizard.net> wrote:
> Peter Dimov wrote:
> > It is not my intention to reopen the discussion, but the answer to
this
> > particular concern is simple:
> >
> > {
> > T * tmp = p;
> > delete tmp;
> > }
>
> That doesn't do any good. The only reason for not wanting pointers
> nulled is to avoid the time wasted doing so; there's no legal use for
> the unnulled value. Not only does this approach not avoid that waste,
it
> compounds it by wasting space creating and initializing a temporary
copy
> of the pointer.
But if your compiler cant optimize away both the copy, and the nullify
in *that* situation, you have far bigger performance problems to worry
about than whether or not delete nulls its argument.
-------------
Mark Williams
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Peter Dimov" <pdimov@mmltd.net>
Date: 2000/10/06 Raw View
"James Kuyper" <kuyper@wizard.net> wrote in message
news:39DD2CEB.79BFD445@wizard.net...
> Peter Dimov wrote:
> >
> > "John G Harris" <john@nospam.demon.co.uk> wrote in message
> > news:Hl8VGKA6ZL35Ew35@jgharris.demon.co.uk...
> > >
> > > And a third half asked "what about those who don't want pointers
> > > nulled?" Your proposed change to the language must include a means
to
> > do
> > > this, as a language feature not a compiler option.
> >
> > It is not my intention to reopen the discussion, but the answer to
this
> > particular concern is simple:
> >
> > {
> > T * tmp = p;
> > delete tmp;
> > }
>
> That doesn't do any good. The only reason for not wanting pointers
> nulled is to avoid the time wasted doing so; there's no legal use for
> the unnulled value.
Technically, you are correct. C++ programmers never access deleted
pointers via (unsigned char *)&p, right? Right? :)
I answered the "academic" question "How do I get the old delete behavior
back, as a language feature?".
> Not only does this approach not avoid that waste, it
> compounds it by wasting space creating and initializing a temporary
copy
> of the pointer.
The performance concerns are, I believe, unfounded. First, an optimizing
compiler would get rid of the unnecessary code, and second, "delete p"
is a much slower operation than "p = 0".
The real problem with the proposal is, as Francis Glassborow pointed
out, "do you want delete to operate on values, on variables, or
something in between?" To take advantage of the fact that delete sets
pointers to 0 you have to remember whether you delete'd the pointer
variable or its value. This is a source of bugs.
--
Peter Dimov
Multi Media Ltd.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: =?ISO-8859-1?Q?J=F6rg?= Barfurth <joerg.barfurth@attglobal.net>
Date: 2000/10/06 Raw View
Am 04.10.00, 19:05:47, schrieb David R Tribble <david@tribble.com> zum=20
Thema Re: NULL "this" pointers:
> Another question I asked was, why *not* let the compiler nullify the
> pointer? =20
One point you don't mention is consistency and othogonality:
'delete' deletes the memory and/or destroys the object pointed to.=20
Therefore it only needs the value of the pointer. That is why delete=20
accepts rvalues and non-modifiable lvalues.
Set-to-null affects an object of pointer type itself. It therefore needs=20
a modifiable lvalue.
To me this alone indicates that these operations are orthogonal and=20
should be separate. Also there often is good reason to delete a pointer=20
rvalue as well as some uses for deleting a constant pointer. These are=20
valid constructs IMHO and the standard should not mandate or recommend a=20
diagnostic for them. (BTW: Some have proposed a mandatory warning. This=20
would be something that currently isn't in the standard: requiring a=20
diagnostic for a well-formed program with well-defined behavior.
But allowing delete for rvalues and constant pointers while requiring=20
delete for modifiable lvalues to set them to null, would be inconsistent.=
=20
It has been pointed out that now the addition of an innocent 'const' may=20
cause subtle changes in program correctness or meaning=20
Effectively it would mean overloading built-in delete on constness, which=
=20
is unprecedented (afaics) and not warranted (imho).
One more thought: What about volatile ?
int * a =3D new int();
int * const b =3D new int();
int * volatile c =3D new int();
int * const volatile =3D new int();
delete a; // now a =3D=3D null
delete b; // now b unusable, but storage of b is unchanged
delete c; // causes accesses (one read, one write ?) to c, which is set=20
to null
// implementation must define the effects of this
delete d; // causes read access to d, but no write
// effects of this are probably distinct from the previous=20
case
> I am willing to accept what tiny overhead there may be to let the
> compiler set deleted pointers to null if it saves me from having to
> do it after every delete.
But many of us don't do it after _every_ delete, but only when it is in=20
fact appropriate[*]. At least some of those may not share your=20
willingness.
[*] It is appropriate (roughly) when there is a pointer variable or=20
member that stays around, that will be reused elsewhere and where using=20
the now invalid value is not prevented by other means. ('Other means' may=
=20
include a scheme for setting to null ALL pointers to the now deleted=20
object or simply that the variable is assigned another non-null pointer=20
value right away).=20
> The other half said it didn't go far enough because it didn't nullify
> every pointer to the object; but surely if you've got multiple
> pointers to an object, that is your problem and not the compiler's.
And if you reuse a deleted pointer lvalue that is your problem too...
But errors are caused by reusing deleted pointer (r)values, whether or=20
not they are stored in the lvalue that was used as the argument of=20
delete.
> Others stated that setting pointers to null created a false sense
> of security. I'm not sure how else you can know that a pointer no
> longer points to anything other than setting it to null.
There may be other invariants that tell you this, but that is besides the=
=20
point.
The point is, that often you cannot know that a pointer variable's value=20
no longer points to anything other than by setting it to null. But if you=
=20
need to know this for some pointer variables, you must ensure that these=20
variables will be set to null no later than when their value no longer=20
points to anything. If the compiler does it for some variables (among=20
them some for which you don't need it), you may be lulled into forgetting=
=20
to do it for others.
C++ is a rather low-level language (and surely this holds where you deal=20
with raw pointers). This means that the compiler doesn't do a lot behind=20
your back. As soon as you introduce such compiler magic, some people will=
=20
take that compiler magic for granted even where it doesn't reach.=20
> Others suggested setting the pointer to an invalid value other than
> null, to cause program crashes later on if the pointer was
> subsequently used. This is very little different than setting it
> to null, which is *the* invalid pointer value, and requires the added
> expense of checking for two values to validate the pointer.
But this mixes two meanings of 'invalid'. Null is a _valid_ value, for a=20
pointer which doesn't point to a valid object. The other use was about a=20
'value' that is not a valid pointer value at all. Legally you can't even=20
check for the latter. By its intended use you shouldn't either (from code=
=20
=96 you do look for it in the debugger, where it serves as an indicator o=
f=20
what caused the problem).
=20
If you have a pointer for which 'not pointing to anything' is a valid=20
state, then use null to represent that state. This includes many (most ?)=
=20
pointer variables for which 'delete the pointee, then reuse the pointer'=20
is a valid use.
If you use a pointer in such a way, that it should not be reused after=20
the pointee is deleted, or that it should always point to a valid object=20
(so null is semantically invalid), then setting that pointer to null may=20
cover up a bug.
Deleting such a pointer (again) violates its contract, as does otherwise=20
reusing the deleted pointer. This is true even if it is just used by code=
=20
that (by chance ?) can cope with null pointer values.
Such a bug may be uncovered earlier if (in a debugging environment only)=20
an _invalid_ pointer value is used, which may often trigger a crash. A=20
crash is much more visible (and easier to debug in most cases) than a bug=
=20
that subtly alters the behaviour of the application.
> michael:
> >| I don't think anyone proposes "std behavior should be changed"
> I am.
To achieve what ? State in simple terms what is achieved by this !
I keep coming up with:
=20
Ensures that some non-constant pointer variables...,
for which it is assured (by other means) that:
- the pointee has dynamic storage duration (and can safely be deleted=20
using the delete operator)
- only modifiable lvalues referring to this pointer will be used to=20
delete the pointee
- or else whenever the lifetime of the pointee (or the ownership of the=20
pointer) ends by other means, they are manually reset to null,
... either point to valid heap objects or are null.=20
But as this is built into the language people would like to see:
Pointers that don't point to valid objects are null.
But the language cannot guarantee this.
I think that changing the language should have a goal that is easily=20
stated, so people can grok the raison d'etre of the new rule.
Regards, J=F6rg
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: llewelly.@@edevnull.dot.com
Date: 2000/10/02 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
> "David Abrahams" <abrahams@mediaone.net> wrote in message
> news:EoOA5.19519$tn.414872@typhoon.ne.mediaone.net...
> > That proposal gets my support!
>
> You know what's funny? It wouldn't break any existing code, except for
> potential uses of "uninitialized". This can be easily solved by using
> __uninitialized or _Uninitialized.
[snip]
Perhaps I am weird, but I would prefer std::uninitialized to
__uninitialized or _Uninitialized .
IOWs, I would rather see new reserved words go into a namespace than
have them mangled.
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Tue, 3 Oct 2000 04:14:36 GMT Raw View
"Gabriel Dos Reis" <gdr@merlin.codesourcery.com> wrote in message
news:m38zs7f6f4.fsf@merlin.codesourcery.com...
> Stealing identifiers from the user namespace and turn them into
> keywords have the potential to break existing codes.
I was thinking that the standard already reserves identifies containing two
underscores or starting with an underscore followed by a capital letter.
Therefore I think no standard-compliant user code can contain
__uninitialized or _Uninitialized.
> Moreover
> requiring users to modifie they programs in order to use
> __uninitialized or _Uninitialized makes them invoke undefined
> behaviour -- semantics I'm not sympathetic with. In short, that is not
> an option.
I am not sure I understand. Nobody would require users to change programs.
The old programs will be guaranteed to compile and run correctly unchanged,
abeit potentially slower because of redundant zero-initializations.
Later on, programmers who profile their code can use __uninitialized to
remove unnecessary initializations.
How nice. You will be able to grep a program for finding all uninitialized
data! That's really sweet.
> Instead, I would suggest the use of the storage class specifier "auto"
> (which is already reserved but much less used).
Not too bad. Well, we can do without any keyword at all, and actually in a
very suggestive manner.
int c = ?; // c is not initialized
while ((c = getch()) != EOF)
statement
Andrei
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/10/03 Raw View
<brangdon@cix.compulink.co.uk> wrote
> Am I right in thinking that after "delete p", accessing p itself is an
> error? Eg:
>
> char *p = new char[2];
> char *p2 = p;
> delete p;
> assert( p == p2 ); // Undefined behaviour?
>
> If so, there is currently no way a conforming program can discover
> whether the compiler changes p or not. It may set p to 0, or 0xdeadbeef,
> or whatever, behind the scenes.
>
> Conceptually the code is similar to:
>
> char *p;
> char *p2;
> assert( p == p2 ); // Undefined behaviour.
>
> On some hardware, address registers are checked for validity when they
> are loaded rather than when they are indirected-through.
This is very interesting, really. Certainly it falls under the general
'using uninited data is UB thing, but I think in that case the compiler is
not requires to load the pointers in the address registers, it can do the
compare in other ways, avoiding problems.
Also, I think in practice there's a big difference between a pointer value
that was legal at one point, and a random pattern. IMHO the former is
unlikely to cause a trap on any real platform. Only dereferencing, or doing
pointer math may explode the program, simple inspecting the value should
not.
> Thus merely
> looking at an undefined variable may cause a hardware fault.
And does the standard treat those two cases as similar?
Paul
---
[ 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: 2000/10/03 Raw View
Gabriel Dos Reis wrote:
>
> "Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
>
> | "David Abrahams" <abrahams@mediaone.net> wrote in message
> | news:EoOA5.19519$tn.414872@typhoon.ne.mediaone.net...
> | > That proposal gets my support!
> |
> | You know what's funny? It wouldn't break any existing code, except for
> | potential uses of "uninitialized". This can be easily solved by using
> | __uninitialized or _Uninitialized.
>
> Stealing identifiers from the user namespace and turn them into
> keywords have the potential to break existing codes. Moreover
That why it should be __uninitialized.
> requiring users to modifie they programs in order to use
> __uninitialized or _Uninitialized makes them invoke undefined
> behaviour -- semantics I'm not sympathetic with. In short, that is not
The suggestion is that __uninitialized would become standard-defined
behavior in some future version of the standard, and until then would be
an implementation-defined extension. It's in the right name space for
just that usage.
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/10/03 Raw View
> Speaking of initializing variables, it's clear that leaving them
> uninitialized is very error-prone. It proved to be the most frequent
source
> of bugs in programs that I have reviewed. It would be nice to initialize
all
> variables by default, and to ask the programmer to write more in the rare
> cases where not initializing a variable makes sense. For example, imagine
> you had a keyword called "uninitialized" that you could use like this:
>
> int i; // initialized to int() by default
> int j = uninitialized; // not initialized
yeah, and lets make the default int() initialize the object to
uninitialized.
>
> The uninitialized keyword would act syntactically like an initializer, and
> semantically would tell the compiler to leave the variable uninitialized.
>
damnit, get rid of the default ctor altogether:
int i; // illformed
int * p; // illformed
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Wed, 4 Oct 2000 06:25:28 GMT Raw View
"michael" <serrano@ozemail.com.au> wrote in message
news:gafC5.17598$O7.232774@ozemail.com.au...
> > int i; // initialized to int() by default
> > int j = uninitialized; // not initialized
>
> yeah, and lets make the default int() initialize the object to
> uninitialized.
I guess a bunch of people will answer to this. Indeed, it came as a surprise
to me too that actually, when you _explicitly_ say:
int i = int();
i is initialized with zero. In general, any explicitly called constructor
for primitive types yields a zero.
This language change made things much cleaner in STL.
> damnit, get rid of the default ctor altogether:
>
> int i; // illformed
> int * p; // illformed
Don't curse :o). This would break existing programs, and, although I
wouldn't mind changing mine, many organizations are not too sanguine about
it.
Andrei
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "michael" <serrano@ozemail.com.au>
Date: 2000/10/04 Raw View
> > > int i; // initialized to int() by default
> > > int j = uninitialized; // not initialized
> >
> > yeah, and lets make the default int() initialize the object to
> > uninitialized.
>
> I guess a bunch of people will answer to this. Indeed, it came as a
surprise
> to me too that actually, when you _explicitly_ say:
>
> int i = int();
>
> i is initialized with zero. In general, any explicitly called constructor
> for primitive types yields a zero.
I half knew this for "new int()" but not auto objects as well.
> This language change made things much cleaner in STL.
Presumably in the zero initialization of a dynamically allocated array of
pointers?
> > [deleted], get rid of the default ctor altogether:
> >
> > int i; // illformed
> > int * p; // illformed
>
> Don't curse :o). This would break existing programs, and, although I
> wouldn't mind changing mine, many organizations are not too sanguine about
> it.
My post was intended to show the arbitrariness of zero. While this is
particularly so for values of an abstract data type, it is clearly not so
for pointers.
thanks for the correction.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: brangdon@cix.compulink.co.uk
Date: 2000/10/04 Raw View
pasa@lib.hu (Balog Pal) wrote (abridged):
> Also, I think in practice there's a big difference between a pointer
> value that was legal at one point, and a random pattern. IMHO
> the former is unlikely to cause a trap on any real platform.
> Only dereferencing, or doing pointer math may explode the
> program, simple inspecting the value should not.
I don't see why. If we accept that random values may trap on load, and
that portions of the address space which used to be readable may stop
being readable once freed, it seems natural to put the two together and
treat freed addresses the same as random, never-owned addresses.
> > Thus merely looking at an undefined variable may cause a
> > hardware fault.
>
> And does the standard treat those two cases as similar?
Yes. Both are undefined behaviour. (Fergus Henderson confirmed my guess
about delete.)
> This is very interesting, really.
Indeed. The behaviour David Tribble wants is not forbidden by the
standard. Perhaps we should prevail upon compiler vendors to implement it
as an extension - non-portable, but undetectable to conforming code.
Admittedly, we'd have to write non-conforming code to take advantage of
it, which probably takes the point away.
Interestingly, not only is an implementation free to set deleted pointers
to NULL, it can do so even if they are declared const.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "David Abrahams" <abrahams@mediaone.net>
Date: 2000/09/29 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> wrote in message
news:st704vnms8ttfc@news.supernews.com...
> Speaking of initializing variables, it's clear that leaving them
> uninitialized is very error-prone. It proved to be the most frequent
source
> of bugs in programs that I have reviewed. It would be nice to initialize
all
> variables by default, and to ask the programmer to write more in the rare
> cases where not initializing a variable makes sense. For example, imagine
> you had a keyword called "uninitialized" that you could use like this:
>
> int i; // initialized to int() by default
> int j = uninitialized; // not initialized
>
> The uninitialized keyword would act syntactically like an initializer, and
> semantically would tell the compiler to leave the variable uninitialized.
That proposal gets my support!
-Dave
---
[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 2000/09/29 Raw View
In article <1cuA5.18517$tn.372886@typhoon.ne.mediaone.net>,
"David Abrahams" <abrahams@mediaone.net> wrote:
>
> "Jim Hyslop" <jim.hyslop@leitch.com> wrote in message
> news:8qql79$4ab$1@nnrp1.deja.com...
[snip]
> > So what benefit do you gain by introducing an artificial value?
>
> The benefit is that you get a crash if you thoughtlessly delete t
> again. If
> t is a member of a class, NULL-ing it could obscure a double-deletion
> bug.
> Doing as I suggest will tend to expose such a bug.
>
> I know there are some cases where an owning pointer may hold a value
> or not (c.f auto_ptr).
Ah, that's what I was getting at. I think we're in agreement then.
Some of the responses earlier in this thread (not necessarily yours)
tended to imply that *any* design where you might delete a pointer that
has been deliberately set to null is an indication of a bad design.
I believe you must always think carefully before applying any standard
rule. Including this one :-)
--
Jim
This message was posted using plain text only. Any hyperlinks you may
see were added by other parties without my permission.
I do not endorse any products or services that may be hyperlinked to
this message.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: "Trevor L. Jackson, III" <fullmoon@aspi.net>
Date: 2000/10/01 Raw View
David Abrahams wrote:
> "Balog Pal" <pasa@lib.hu> wrote in message
> news:088c01c02942$bc2f4a10$d30e38c3@bpnt...
> >
> > "David Abrahams" <abrahams@mediaone.net> wrote
> >
> > [deadbeef instead of 0]
> > > The benefit is that you get a crash if you thoughtlessly delete t again.
> > If
> > > t is a member of a class, NULL-ing it could obscure a double-deletion
> bug.
> >
> > But that bug is not at all a bug. It is specified that delete on 0 is
> > ignored. So calling delete on a pointer variable that either points to
> > deletable thing or set to 0 is good, and if you set the value to 0 always
> > having no valid pointee, you can issue as many deletes as you want.
>
> Sorry, I mis-typed. I meant a double-destruction bug, such as can be induced
> by the popular but usually misapplied construct:
>
> foo->~Foo();
> new ((void*)foo) Foo(...);
A couple months ago I asked about this construct in comp.lang.c++ and got no
responses. Your claim that this is mostly misapplied is interesting. Would
you care to describe the conditions under which you belive this construct is
properly applied and what is wrong with the usual applications?
The situation I was trying to resolve was related to input. The object being
read is accessible via a pointer. Having successfully read the components it
necessary to invoke some method to create the target object. It appears to me
that one can use a ctor taking the components as arguments to create a temporary
and then assign the temporary to the object, or one can use the same ctor in
place. In one case assignment is used, in the other an explicit dtor.
Which do you prefer and why? Is there a third approach that I've neglected (a
ctor taking an istream argument is insufficiently general).
---
[ 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 Abrahams" <abrahams@mediaone.net>
Date: Mon, 2 Oct 2000 04:08:34 GMT Raw View
"Trevor L. Jackson, III" <fullmoon@aspi.net> wrote in message
news:39D3A05C.F2CDF56D@aspi.net...
> David Abrahams wrote:
>
> > "Balog Pal" <pasa@lib.hu> wrote in message
> > news:088c01c02942$bc2f4a10$d30e38c3@bpnt...
> > >
> > > "David Abrahams" <abrahams@mediaone.net> wrote
> > >
> > > [deadbeef instead of 0]
> > > > The benefit is that you get a crash if you thoughtlessly delete t
again.
> > > If
> > > > t is a member of a class, NULL-ing it could obscure a
double-deletion
> > bug.
> > >
> > > But that bug is not at all a bug. It is specified that delete on 0 is
> > > ignored. So calling delete on a pointer variable that either points to
> > > deletable thing or set to 0 is good, and if you set the value to 0
always
> > > having no valid pointee, you can issue as many deletes as you want.
> >
> > Sorry, I mis-typed. I meant a double-destruction bug, such as can be
induced
> > by the popular but usually misapplied construct:
> >
> > foo->~Foo();
> > new ((void*)foo) Foo(...);
>
> A couple months ago I asked about this construct in comp.lang.c++ and got
no
> responses. Your claim that this is mostly misapplied is interesting.
Would
> you care to describe the conditions under which you belive this construct
is
> properly applied and what is wrong with the usual applications?
The usual problem arises when Foo's constructor may throw an exception. In
that case, there is always some other code which thinks it has a Foo to
manage (and eventually destroy), even though stack unwinding from the
exception will ensure that there is no Foo to destroy.
> The situation I was trying to resolve was related to input. The object
being
> read is accessible via a pointer. Having successfully read the components
it
> necessary to invoke some method to create the target object. It appears
to me
> that one can use a ctor taking the components as arguments to create a
temporary
> and then assign the temporary to the object, or one can use the same ctor
in
> place. In one case assignment is used, in the other an explicit dtor.
>
> Which do you prefer and why? Is there a third approach that I've
neglected (a
> ctor taking an istream argument is insufficiently general).
I always opt for assignment. It doesn't pay to "play god with object
lifetimes" in C++ ;->
but-sometimes-it-is-good-to-euthanize-old-crufty-code-ly y'rs,
dave
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/10/02 Raw View
"David Abrahams" <abrahams@mediaone.net> wrote in message
news:EoOA5.19519$tn.414872@typhoon.ne.mediaone.net...
> That proposal gets my support!
You know what's funny? It wouldn't break any existing code, except for
potential uses of "uninitialized". This can be easily solved by using
__uninitialized or _Uninitialized.
It wouldn't break existing code becaused variables of primitive types that
are not initialized have undefined values. Zero is a particular value that
snuggles comfortably in the "undefined value" realm :o). Oh well.
Andrei
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/10/02 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
| "David Abrahams" <abrahams@mediaone.net> wrote in message
| news:EoOA5.19519$tn.414872@typhoon.ne.mediaone.net...
| > That proposal gets my support!
|
| You know what's funny? It wouldn't break any existing code, except for
| potential uses of "uninitialized". This can be easily solved by using
| __uninitialized or _Uninitialized.
Stealing identifiers from the user namespace and turn them into
keywords have the potential to break existing codes. Moreover
requiring users to modifie they programs in order to use
__uninitialized or _Uninitialized makes them invoke undefined
behaviour -- semantics I'm not sympathetic with. In short, that is not
an option.
Instead, I would suggest the use of the storage class specifier "auto"
(which is already reserved but much less used).
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/10/02 Raw View
"James Kuyper" <kuyper@wizard.net> wrote in message
> In general, when I'm do things like that, the const pointer is going out
> of scope immediately after the delete; the last thing I want is for
> 'delete' to waste time setting it to 0.
Note, that the compiler routinely optimize away all such things.
{
int i;
...
i = 0;
} // i disappears here
that i = 0 does not happen in optimized build unless i was volatile. delete
setting to 0 at end of scope would behave alike.
> Your const_cast<>() 'solution'
> only makes it worse: a temporary pointer is created, set to 0, and is
> then released.
Same applies here. All that code is discarded.
Paul
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/10/02 Raw View
"David R Tribble" <david@tribble.com> wrote in message
> >> OTOH, Nevin Liber gave a (nay, the only) convincing argument why
> >> the "delete should nullify its pointer" is a dangerous thing.
> class Foo
> {
> private:
> Bar * m_bar; // [P]
> public:
> void release()
> {
> delete m_bar; // [A] Assumes m_bar is set to null
> }
> };
> Then along comes another programmer who changes the type of the
> pointer to be a const pointer:
>
> // Second revision
> Bar *const m_bar; // [P]
If that is a single change, it is an obvious bad move, bringing in a bug.
When you change the type of a member you should visit all the places of use
(not just trust the compiler will flag all uses as error). Such a change
explicitly means you need to remove public Release() from the interface as
an unimplemetable thing, and any similar functions that very likely exist in
the same class (if you have a manual Release, probably there's something to
alloc a new bar, etc.)
> Now the delete at [A] compiles silently, deleting object *m_bar
> but not setting the m_bar pointer to null (because it can't).
> So the second programmer has created a lurking bug that is not
> evident until [B] is executed.
>
> But this example assumes that the compiler is silent about [A].
> My original suggestion proposed that a diagnostic (warning) would
> be issued when deleting through const pointers, even if they are
> about to go out of scope, since this is a sure sign of creating
> dangling const pointers.
Yeah, I also said a diagnostic would be needed in the case. But I fail to
recognize that example as a good one against nullifying delete even if the
warnings are off.
Paul
---
[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 2000/09/27 Raw View
In article <qmWy5.14591$tn.217917@typhoon.ne.mediaone.net>,
"David Abrahams" <abrahams@mediaone.net> wrote:
>
> "David R Tribble" <david@tribble.com> wrote in message
> news:39CBC7B0.A886FF8@tribble.com...
> > "Peter Dimov" <pdimov@mmltd.net> wrote
> > >> Setting p to zero makes the error (slightly) more easily
detectable.
> > >> (And a second 'delete' harmless.)
> >
> > David Abrahams wrote:
> > > So it makes one error (a dereference through p) slightly more
> > > detectable*, but it completely hides another kind of error (a
second
> > > delete). In this case I think the cure is far worse than the
disease.
> >
> > So I take it this is an argument against ever setting deleted
pointers
> > to null, even explicitly?
>
> Not at all. It is an argument against automatically setting all
> deleted
> pointers to null automatically. In debug builds at least, we should
> write
> code that exposes unintentional, careless programming. If the code
> crashes
> or asserts in a debug build we are forced to deal with a problem or
> mistaken
> assumption before it creeps into a shipping build and causes worse
> damage
> downstream.
>
> It is arguable that such a behavior is desirable in a shipping build,
and
> how much resiliency to such errors we wish to deliver in a shipping
build is
> a policy choice worthy of careful consideration. You'll often find,
however,
> that such ad-hoc protections against programming errors are really
just an
> unneccessary efficiency hit if debug builds have been tested with the
> opposite policy.
>
> I would suggest in debug builds, you consider "delete p, p = <invalid
> non-null pointer>"
> Then in shipping builds, you may choose "delete p, p = 0", but you
> probably
> won't need it.
I presume you mean something like this:
void f()
{
T * t=new T;
// .... lots of code ....
delete t;
#ifdef NDEBUG
t = reinterpret_cast<T *>(0xdeadbeef);
#endif
// .... lots more code ....
}
I don't see the benefit of your suggestion, unless the compiler runs on
a platform where a null pointer is a valid address (16-bit DOS, for
example - 0000:0000 is the first entry in the interrupt vector, if I
recall correctly).
On any other platform, attempting to follow a null pointer will cause
the same problems as attempting to follow an invalid, non-null pointer.
So what benefit do you gain by introducing an artificial value?
The other problem with your suggestion is that it may be difficult, if
not impossible, to come up with an invalid, non-null pointer value that
can be used across platforms, for those of us involved in portable code.
--
Jim
This message was posted using plain text only. Any hyperlinks you may
see were added by other parties without my permission.
I do not endorse any products or services that may be hyperlinked to
this message.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/27 Raw View
[shamelessly summarizing]
>> delete p, p = NULL; // Do this at every delete
>> (It's a shame that 'delete' doesn't do this for you automatically.)
> I would argue that it's up to the programmer to nullify all the
> pointers. Surely if he's got multiple pointers to the same object,
> he presumably has a way of keeping track of them. But the compiler
> can't, and shouldn't have to, do this.
> OTOH, Nevin Liber gave a (nay, the only) convincing argument why
> the "delete should nullify its pointer" is a dangerous thing.
No-one gave a convincing argument why "delete should nullify its pointer"
would be a good thing.
---
[ 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 Abrahams" <abrahams@mediaone.net>
Date: 2000/09/27 Raw View
"Jim Hyslop" <jim.hyslop@leitch.com> wrote in message
news:8qql79$4ab$1@nnrp1.deja.com...
>
> I presume you mean something like this:
>
> void f()
> {
> T * t=new T;
> // .... lots of code ....
> delete t;
> #ifdef NDEBUG
> t = reinterpret_cast<T *>(0xdeadbeef);
> #endif
> // .... lots more code ....
> }
Yes.
> I don't see the benefit of your suggestion, unless the compiler runs on
> a platform where a null pointer is a valid address (16-bit DOS, for
> example - 0000:0000 is the first entry in the interrupt vector, if I
> recall correctly).
>
> On any other platform, attempting to follow a null pointer will cause
> the same problems as attempting to follow an invalid, non-null pointer.
> So what benefit do you gain by introducing an artificial value?
The benefit is that you get a crash if you thoughtlessly delete t again. If
t is a member of a class, NULL-ing it could obscure a double-deletion bug.
Doing as I suggest will tend to expose such a bug.
I know there are some cases where an owning pointer may hold a value or not
(c.f auto_ptr). In these cases, it makes sense to NULL the pointer when it
doesn't hold a value. It's a convenient optimization, saving time and space
over the alternative of maintaining a bool to indicate whether a value is
held. Granted.
In other cases, you know whether the pointer is supposed to be holding a
value at any given point in the code. In these cases (and I think this
should be the default), my suggestion is more reliable.
This discussion reminds me of arguments often had about C++ and Java. Some
Java proponent will claim that GC prevents bugs, and some C++ fanatic will
counter that it just covers them up by creating leaks. I guess I'm the C++
fanatic in this argument ;-)
> The other problem with your suggestion is that it may be difficult, if
> not impossible, to come up with an invalid, non-null pointer value that
> can be used across platforms, for those of us involved in portable code.
Sorry, I'm just not very impressed with that argument! Nearly every
"portable" program contains some platform-specific configuration. Just
isolate the constant behind a name in a header file.
-Dave
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/28 Raw View
> When I 'delete' a pointer (assume non-shared ownership) (yes, in real
> world programs,) this pointer is an 'owning pointer'. In addition to
> this, no live aliases exist at this point.
>
> I maintain an invariant on owning pointers. The invariant is that they
> can be safely deleted, that is, they either point to something that was
> allocated with new (and not delete'd, of course), or they are NULL.
>
> Under the current 'delete' semantics to maintain this invariant I have
> to set pointers either to NULL or to a new block of storage immediately
> after 'delete' (if the pointer persists after the delete, i.e. this is
> not a destructor or the pointer does not get out of scope right after
> the delete.)
>
> The new 'delete' semantics would maintain this invariant automatically.
>
> Under these assumptions, a second delete request on an owning pointer
> is not an error - because a 'delete' on an owning pointer is never an
> error - this is what the invariant states.
>
> What's so academic in that? auto_ptr does the same. So would any class
> that permits explicit acquire/release.
auto_ptr fully supports and expresses your restricted notion of pointers -
please use that.
Or write your own template <typename T> dispose (T*&);
Pointers are the sharpest tool in the shed. Lets not blunt them.
> (Yes, this means that I never delete an rvalue or a non-modifiable
> lvalue; and I never 'delete this'.)
nullifying the pointer is often wasted, and sometimes definitely not wanted.
for example, if we write our own operator delete() we don't always
de-allocate memory. In this case, we may do a placement new immediately
after.
---
[ 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: 2000/09/28 Raw View
michael wrote:
...
> for example, if we write our own operator delete() we don't always
> de-allocate memory. In this case, we may do a placement new immediately
> after.
Why would you delete it if you're not deallocating memory? Just call the
destructor directly, if you want to clear the memory for the following
placement new.
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/28 Raw View
pdimov@techno-link.com writes:
| In article <m3n1gxq26l.fsf@merlin.codesourcery.com>,
| Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
|
| > So, let me make some clarifications.
| >
| > 'Delete'ing a non null pointer (in real world programs) triggers
| > (among other things) request for memory release; and I'm considering
| > the problem from that point of view. Not from an academic point fo
| > view -- not that that perspective is not interesting, but just because
| > it focuses on purely theorical point of view and ignores practical
| > considerations.
|
| Ok, I'll try to restate my point.
|
| When I 'delete' a pointer (assume non-shared ownership) (yes, in real
| world programs,) this pointer is an 'owning pointer'. In addition to
| this, no live aliases exist at this point.
Yes, in an ideal world that is what happens -- that is what we strive
for.
| I maintain an invariant on owning pointers. The invariant is that they
| can be safely deleted, that is, they either point to something that was
| allocated with new (and not delete'd, of course), or they are NULL.
|
| Under the current 'delete' semantics to maintain this invariant I have
| to set pointers either to NULL or to a new block of storage immediately
| after 'delete' (if the pointer persists after the delete, i.e. this is
| not a destructor or the pointer does not get out of scope right after
| the delete.)
|
| The new 'delete' semantics would maintain this invariant automatically.
Well, I understand you concern; but I think it is a particular case of
concerns and the proposed semantics doesn't handle the following
struct list_node_base {
void* data;
// ...
};
template<typename T>
struct list_node : list_node_base {
void deallocate_data { delete ((T*) data); }
};
which I think is not uncommon.
Furthermore, the language as is now provides the necessary abstraction
tools for achieving the effects you're after:
template<typename T> void my_fancy_nullifying_delete(T*&);
which automatically can set pointers to NULL; as a bonus you can catch
use of non modifiable lvalues.
In short, there is no need for core language change --which, in some
cases, will just give a false sense of security. The necessary
infrastructures are already there.
| Under these assumptions, a second delete request on an owning pointer
| is not an error - because a 'delete' on an owning pointer is never an
| error - this is what the invariant states.
|
| What's so academic in that? auto_ptr does the same. So would any class
| that permits explicit acquire/release.
|
| (Yes, this means that I never delete an rvalue or a non-modifiable
| lvalue; and I never 'delete this'.)
What is academic is that you're implicitly assuming that all real
world programs are operating under your model.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/28 Raw View
> > for example, if we write our own operator delete() we don't always
> > de-allocate memory. In this case, we may do a placement new immediately
> > after.
>
> Why would you delete it if you're not deallocating memory? Just call the
> destructor directly, if you want to clear the memory for the following
> placement new.
>
ok,
bad example. others have posted better.
This thread's gone all wrong.
The proposition "std behaviour is a shame" should be backed up by an
argument.
As for proving "it's not a shame", there is no case to answer.
I don't think anyone proposes "std behavior should be changed"
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/28 Raw View
"michael" <serrano@ozemail.com.au> writes:
[...]
| The proposition "std behaviour is a shame" should be backed up by an
| argument.
Yes, I asked for such argument but didn't get any convincing one.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/28 Raw View
"David Abrahams" <abrahams@mediaone.net> wrote
[deadbeef instead of 0]
> The benefit is that you get a crash if you thoughtlessly delete t again.
If
> t is a member of a class, NULL-ing it could obscure a double-deletion bug.
But that bug is not at all a bug. It is specified that delete on 0 is
ignored. So calling delete on a pointer variable that either points to
deletable thing or set to 0 is good, and if you set the value to 0 always
having no valid pointee, you can issue as many deletes as you want.
> Doing as I suggest will tend to expose such a bug.
It will expose a non-bug, and also cripple a good behavior. deadbeef is
helping when your protocol does not guarantee the assertation above. What is
probably a dangerous situation in itself.
> In other cases, you know whether the pointer is supposed to be holding a
> value at any given point in the code.
For 1..1 cardnality you may be better off with reference. Well, those can't
be reassigned limiting use in a plenty of situations...
> In these cases (and I think this
> should be the default), my suggestion is more reliable.
This is no way a default situation. Poiters are preferred at 0..1
cardinality, where it is a valid and meaningful state to have a 0.
Paul
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/09/28 Raw View
"David R Tribble" <david@tribble.com> wrote in message
news:39CBC569.ED110874@tribble.com...
> michael wrote:
> > Is it also a shame that pointers aren't initialized to NULL?
>
> Yep. I have to do it myself explicitly in all my constructors.
>
> MyClass::MyClass(): m_ptr(NULL), ...
> { ... }
>
> and whenever I allocate an array of pointers.
I couldn't agree more.
I think a very important language and library design rule is to make it easy
to write safe and correct stuff, and increasingly ask the programmer for
more syntax as she wants to do things that are more efficient but also more
error-prone.
C++ does support this philosophy in some areas, but not in some others for
various (mainly compatibility) reasons.
Speaking of initializing variables, it's clear that leaving them
uninitialized is very error-prone. It proved to be the most frequent source
of bugs in programs that I have reviewed. It would be nice to initialize all
variables by default, and to ask the programmer to write more in the rare
cases where not initializing a variable makes sense. For example, imagine
you had a keyword called "uninitialized" that you could use like this:
int i; // initialized to int() by default
int j = uninitialized; // not initialized
The uninitialized keyword would act syntactically like an initializer, and
semantically would tell the compiler to leave the variable uninitialized.
It is my belief that it is time for a language that learns from the huge
pioneering effort that C++, and its more academinc predecessors, mean to the
computing industry; that gets rid of the object-orientation exaggerations
and hysteria; that has an easy enough syntax; that scales up to allow
expressing advanced design idioms; and that allow you to model complex
worlds in efficient ways.
Andrei
---
[ 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: pdimov@techno-link.com
Date: 2000/09/28 Raw View
In article <RUGA5.7925$O7.152788@ozemail.com.au>,
"michael" <serrano@ozemail.com.au> wrote:
> This thread's gone all wrong.
I think I agree with this.
> The proposition "std behaviour is a shame" should be backed up by an
> argument.
I never stated that the "std behaviour is a shame."
The argument is the physical vs logical const correctness discrepancy.
> As for proving "it's not a shame", there is no case to answer.
> I don't think anyone proposes "std behavior should be changed"
Such a change will have an impact on lots of existing code and it's
unrealistic to expect it.
The discussion, as I understand it, was about whether the more
restricted 'delete' semantics are (1) viable, (2) better.
This discussion does indeed deserve the 'academic' label
because 'delete' is a low-level primitive and whether it's more
powerful than necessary is not that important.
--
Peter "I do use auto_ptr, thank you very much" Dimov
Multi Media Ltd.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: pdimov@techno-link.com
Date: 2000/09/28 Raw View
In article <m3r964g0na.fsf@merlin.codesourcery.com>,
Gabriel Dos Reis <gdr@codesourcery.com> wrote:
> pdimov@techno-link.com writes:
> | The new 'delete' semantics would maintain this invariant
automatically.
>
> Well, I understand you concern; but I think it is a particular case of
> concerns and the proposed semantics doesn't handle the following
>
> struct list_node_base {
> void* data;
> // ...
> };
>
> template<typename T>
> struct list_node : list_node_base {
> void deallocate_data { delete ((T*) data); }
> };
>
> which I think is not uncommon.
A perfectly valid counter-example. I've used this myself. Sigh. :-)
> What is academic is that you're implicitly assuming that all real
> world programs are operating under your model.
Not at all.
--
Peter Dimov
Multi Media Ltd.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/28 Raw View
Jim Hyslop <jim.hyslop@leitch.com> writes:
| In article <m3itrlq217.fsf@merlin.codesourcery.com>,
| Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
| > Jim Hyslop <jim.hyslop@leitch.com> writes:
| >
| > | In article <m3zol3rrwh.fsf@merlin.codesourcery.com>,
| > | Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
| > | [snip]
| > | > I guess, that is a matter of opinion. Releasing a twice a storage
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| > | > is bug or a design error.
| > | I don't agree. There are design situations where a pointer can be
| > | released prior to the containing object being destroyed. Why is that
| > | a
| > | design error?
| >
| > I'm concerned with the *contained* object, not the containing object.
| Sorry about the typo - I meant contained. So, why is it an error to
| delete the same pointer twice? Assuming, of course, that you set it to
| null after the first delete.
If you set the pointer to NULL after the first delete, then the second
isn't a storage release; thus is no bug to look for.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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 Abrahams" <abrahams@mediaone.net>
Date: 2000/09/28 Raw View
"Balog Pal" <pasa@lib.hu> wrote in message
news:088c01c02942$bc2f4a10$d30e38c3@bpnt...
>
> "David Abrahams" <abrahams@mediaone.net> wrote
>
> [deadbeef instead of 0]
> > The benefit is that you get a crash if you thoughtlessly delete t again.
> If
> > t is a member of a class, NULL-ing it could obscure a double-deletion
bug.
>
> But that bug is not at all a bug. It is specified that delete on 0 is
> ignored. So calling delete on a pointer variable that either points to
> deletable thing or set to 0 is good, and if you set the value to 0 always
> having no valid pointee, you can issue as many deletes as you want.
Sorry, I mis-typed. I meant a double-destruction bug, such as can be induced
by the popular but usually misapplied construct:
foo->~Foo();
new ((void*)foo) Foo(...);
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/29 Raw View
pdimov@techno-link.com writes:
[...]
| This discussion does indeed deserve the 'academic' label
| because 'delete' is a low-level primitive and whether it's more
| powerful than necessary is not that important.
I think, we could be in violent agreement here.
Row pointers are low-level abstractions and I think no matter what we
do with them we'll find one more "incorrect" semantics with them --
unless we turn them into high-level abstractions.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: John G Harris <john@nospam.demon.co.uk>
Date: 2000/09/29 Raw View
In article <8qqftg$1dg$1@nnrp1.deja.com>, pdimov@techno-link.com writes
<snip>
>Ok, I'll try to restate my point.
>
>When I 'delete' a pointer (assume non-shared ownership) (yes, in real
>world programs,) this pointer is an 'owning pointer'. In addition to
>this, no live aliases exist at this point.
>
>I maintain an invariant on owning pointers. The invariant is that they
>can be safely deleted, that is, they either point to something that was
>allocated with new (and not delete'd, of course), or they are NULL.
<snip>
So the pointer is set to NULL to indicate a change of state, and later
on you do an action that is conditional on the state.
There's nothing wrong with this, but why must it be part of the C++
language? What about people who don't want the pointer NULLed?
John
--
John Harris
mailto:john@jgharris.demon.co.uk
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/25 Raw View
> 2. You can release in a single step:
> // instead of delete p, p==NULL;
> p.release(); // delete the owned ptr.
seduced by the name, I was caught with my trousers down. )blush(
p.reset(); // delete the owned ptr
(release just releases the ptr from auto_ptr)
---
[ 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 <david@tribble.com>
Date: 2000/09/25 Raw View
David R Tribble <david@tribble.com> wrote:
>> Please provide an example where setting a recently deleted pointer
>> to null creates a bug. Otherwise, I don't believe you.
Greg Comeau wrote:
> Pardon? That kind of talk is unnecessary.
>
> Please note that I did not say that delete/delete'ing did it.
> I was talking in general about pointer problems and of
> nulling pointers.
Okay, fine.
> [...]
> As to delete setting a pointer to null possibly creating
> a bug I've never thought about that yet. Now that you
> mention it, I wonder above the following:
> [...]
1) Used defined and/or class operator delete. It would seem
> that this too would have to abide by the same semantics,
> but I just can't go the full mile that that would always
> make sense.
Operator delete must abide by the semantics of being passed a
possibly null pointer. Says so in the standard.
> 2) Things like shared memory, multiple threads, etc.
> (C++ doesn't support these per se, but they're still indirectly
> involved).
Yes. C++ has no notion of this. However, nulling a pointer in one
thread ought to disallow access to the now-deleted object in other
threads. This requires synchronization of some sort, though, which
is beyond plain C++.
> 3) Multiple pointers to the same object
> (I argue that if delete should null one of them, then delete
> should null all of them)
I would argue that it's up to the programmer to nullify all the
pointers. Surely if he's got multiple pointers to the same object,
he presumably has a way of keeping track of them. But the compiler
can't, and shouldn't have to, do this.
I'm talking about the simple case of deleting through a single
pointer.
OTOH, Nevin Liber gave a (nay, the only) convincing argument why
the "delete should nullify its pointer" is a dangerous thing.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: Tue, 26 Sep 2000 00:38:02 GMT Raw View
Nevin Liber wrote:
> I'm not against partial solutions; I'm against BAD solutions that
> cause more subtle bugs than the obvious ones that they are purporting
> to fix.
>
> If this feature [the delete nullifying the pointer] were added,
> declaring/not declaring something const would now change the run-time
> semantics of a C++ program instead of just the compile-time semantics;
> this is not a good idea.
>
> [example omitted]
>
> the code now has a subtle double delete bug. All because of this
> seemingly innocuous proposal, which has the subtle effect that
> adding/removing a const declaration subtly changes the run-time
> semantics of the code in a way that, even at a minimum, is not warned
> about at compile time.
>
> Like I said, this is not a good idea...
Good point. A convincing argument against the feature (the only
convincing argument so far).
However, I originally proposed that a delete on a const pointer should
cause a warning to be issued by the compiler. If for no other reason,
than because the delete will create a dangling const pointer (even
if the pointer is about to go out of scope).
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: Tue, 26 Sep 2000 00:38:48 GMT Raw View
Andrei Alexandrescu wrote:
>> The thing with delete nullifying its argument is that it promises
>> more that it can actually do...
David R Tribble wrote:
>> Such as? "Delete the object pointed to by a pointer, then invalidate
>> the pointer." What more should it do?
James Kuyper wrote:
> Zero all of the pointers to the same piece of memory. Which it can't
> do. Which it must do, to justify the sense of safety that some people
> mistakenly derive from it.
How is this any different than the ("false") sense of safety derived
by the programmer setting a just-deleted pointer to null explicitly?
You've described the situation of having several pointers point to
the same object and then deleting that object. Surely that's a
problem for the programmer who wrote the code, and not a problem for
the compiler. It he's going to have multiple pointers laying around,
then he should take the responsibility of keeping track of all of
them, and subsequently nullifying them when the shared object is
deleted. The compiler can't, and shouldn't, assume more than one
object pointer per delete.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.com
======================================= MODERATOR'S COMMENT:
Warning: The Standard-related content in this thread branch is flatlining...
---
[ 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 <david@tribble.com>
Date: Tue, 26 Sep 2000 00:39:05 GMT Raw View
Gabriel Dos Reis wrote:
>> [...]
>> Furtermore I won't certainly want to get noise from the compiler each
>> time I don't use a modifiable lvalue in a delete-expression.
David R Tribble <david@tribble.com> writes:
>| How often is that? I would wager that less than 1% of your deletes
>| ever do this.
Gabriel Dos Reis wrote:
> Where does your figure come from?
I was talking about how uncommon it is to delete an object through a
*const* pointer.
> Furthermore, if a program happens to release twice the same storage
> then there must be something really wrong either with the program or
> with the design; requiring `delete' -- in that case -- to set
> automatically the pointer to NULL is just papering over the problem.
On the other hand, some people find it useful to be able to delete
an object within a destructor (that object being pointed to by a
member of the destructed object) by simply saying 'delete p' and
not having to check to see if the pointer 'p' is null first. This
assumes that the pointed-to object may have been previously deleted
by another member function. In this case, two deletes do not imply
two deallocations. But to work properly, this idiom relies on the
fact that the pointer is set to null immediately after the object
is deleted the first time.
BTW, Pascal implementations set deleted pointers to nil automatically
('dispose p'). I don't recall hearing any complaints about it.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: James Kuyper <kuyper@wizard.net>
Date: Tue, 26 Sep 2000 03:02:28 GMT Raw View
David R Tribble wrote:
>
> Andrei Alexandrescu wrote:
> >> The thing with delete nullifying its argument is that it promises
> >> more that it can actually do...
>
> David R Tribble wrote:
> >> Such as? "Delete the object pointed to by a pointer, then invalidate
> >> the pointer." What more should it do?
>
> James Kuyper wrote:
> > Zero all of the pointers to the same piece of memory. Which it can't
> > do. Which it must do, to justify the sense of safety that some people
> > mistakenly derive from it.
>
> How is this any different than the ("false") sense of safety derived
> by the programmer setting a just-deleted pointer to null explicitly?
Not at all. My argument was against that practice. I'm against making it
automatic for the same reason I'm against doing it manually. I treat
pointers that have been deleted exactly like pointers that have never
been initialized - I design my code so they don't get used. I can
usually do so quite elegantly with little or no efficiency costs; well
designed code isn't even tempted to use 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/26 Raw View
"David R Tribble" <david@tribble.com> wrote in message
> OTOH, Nevin Liber gave a (nay, the only) convincing argument why
> the "delete should nullify its pointer" is a dangerous thing.
You mean this example:
class TMe
{
public:
TMe * me;
TMe() { me = this; }
};
void silly()
{
TMe * myself = new TMe;
delete myself.me;
}
Why exactly is that a problem? delete should be an atomic operation, isn't
it? That does the following: call dtors, then deallocate memory and set the
pointer to 0. The last two seems to cause the problem, if dealloc comes
forst, write as second, but if that is inside the atom, it's not a problem.
Also it can be done in the other order: set first, dealloc then.
Certainly one could construct a more complex example, when the pointer is
located inside a dynamically allocated subobject of the class but that is
probably error-prone in such use even without autonulling delete.
Paul
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/26 Raw View
"Nevin Liber" <nevin@enteract.com> wrote
> class TOtherClass
> {
> private:
> TClass * theClass;
> public:
> void DeleteTheClass()
> {
> delete theClass;
> }
> };
> Mr. Const Cop comes along and is tasked with maintaining the code. He
looks
> at TOtherClass::DeleteTheClass() and notices that it doesn't seem to
modify
> any of the non-static member variables of TOtherClass.
Are we talking about the case when delete sets pointer to 0 or when not? In
the first case CC has bad eyes. In the second only bad brains.
> Sounds like a good
> candidate to become a const member function, doesn't it?
No way. That function modifies the state of the class, and should in no case
be const. (This case somewhat resembles the shallow/deep constness of a
class when it holds pointers. The behavior should be well documented, if not
trouble comes soon.)
> Now it looks like:
>
> void TOtherClass::DeleteTheClass() const
> {
> delete theClass;
> }
>
> No compiler warnings. Not a peep.
In the pointer-nullizing delete case it woud trigger an error. If you're
talking abut the case when deleting a const pointer shoud leave the value
alone, it was also suggested to give a warning about that. Certailny if the
warnings are set to off, no peep, but who is to be blamed?
> Mr. Const Cop is satisfied in the knowledge of improving the code and a
> job well done.
Never allow cops going near your stuff. ;->
> Even assuming we survive the obvious bug:
>
> void WhatShouldIDo()
> {
> TOtherClass otherClass;
>
> otherClass.DeleteTheClass();
> if (otherClass.IsTheClassSet()) {
> DestroyTheWorld()
> } else {
> MakeAPopTart();
> }
> }
>
> the code now has a subtle double delete bug. All because of this
seemingly
> innocuous proposal, which has the subtle effect that adding/removing a
const
> declaration subtly changes the run-time semantics of the code in a way
that,
> even at a minimum, is not warned about at compile time.
You're seriously bending facts here. If delete is specified to modify the
underlying pointer, but ot doing so in case it is const, adding a const is
no way to be called a 'subtle' change. It is a cardinal change. And
modifying code based on wrong assumptations will lead to tons of different
problems, you need no change in the language to reach that.
Paul
---
[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 2000/09/26 Raw View
In article <m3itrlq217.fsf@merlin.codesourcery.com>,
Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
> Jim Hyslop <jim.hyslop@leitch.com> writes:
>
> | In article <m3zol3rrwh.fsf@merlin.codesourcery.com>,
> | Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
> | [snip]
> | > I guess, that is a matter of opinion. Releasing a twice a storage
> | > is bug or a design error.
> | I don't agree. There are design situations where a pointer can be
> | released prior to the containing object being destroyed. Why is that
> | a
> | design error?
>
> I'm concerned with the *contained* object, not the containing object.
Sorry about the typo - I meant contained. So, why is it an error to
delete the same pointer twice? Assuming, of course, that you set it to
null after the first delete.
As an over-simplified example, what is wrong with this:
class U;
class T
{
U *ptr;
public:
T() : ptr(0) {}
void someFunction()
{
// assign 'ptr' a value
}
void anotherFunction()
{
delete ptr;
ptr=0;
}
~T() { delete ptr; }
};
Suppose a valid sequence of operations is:
void f()
{
T t;
// some code here
t.someFunction();
// more code here
t.anotherFunction();
// more code here.
}
If I understand your criteria correctly, you consider class T to be
badly designed simply because ptr will be deleted twice. Now, *why* is
that a bad design?
--
Jim
This message was posted using plain text only. Any hyperlinks you may
see were added by other parties without my permission.
I do not endorse any products or services that may be hyperlinked to
this message.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/26 Raw View
David R Tribble <david@tribble.com> writes:
| Gabriel Dos Reis wrote:
| >> [...]
| >> Furtermore I won't certainly want to get noise from the compiler each
| >> time I don't use a modifiable lvalue in a delete-expression.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| David R Tribble <david@tribble.com> writes:
| >| How often is that? I would wager that less than 1% of your deletes
| >| ever do this.
|
| Gabriel Dos Reis wrote:
| > Where does your figure come from?
|
| I was talking about how uncommon it is to delete an object through a
| *const* pointer.
Fair enough. But that wasn't appearant from your previous message --
an expression which isn't a "modifiable lvalue" is either a
non-modifiable lvalue or an rvalue, no? :-)
| > Furthermore, if a program happens to release twice the same storage
| > then there must be something really wrong either with the program or
| > with the design; requiring `delete' -- in that case -- to set
| > automatically the pointer to NULL is just papering over the problem.
|
| On the other hand, some people find it useful to be able to delete
| an object within a destructor (that object being pointed to by a
| member of the destructed object) by simply saying 'delete p' and
| not having to check to see if the pointer 'p' is null first.
My point is that those people have the necessary abstraction machinary
at their disposable to make sure their `delete's are safe. If they
think they have the right to say `delete p', then logically checking
for null first should not change the outcome.
| ... This
| assumes that the pointed-to object may have been previously deleted
| by another member function.
This is precisely what I'm questioning: from a software methodoly
point of view, how reliable is a program which deletes unconditionally
deletes every pointers it founds?
| ... In this case, two deletes do not imply
| two deallocations. But to work properly, this idiom relies on the
| fact that the pointer is set to null immediately after the object
| is deleted the first time.
Then in that case, I think that from a software methodology point of
view, the programmer should make it clear that two deallocations are
safe, by explicitly setting the pointer to NULL after the first
deletion. If `delete p' were to unconditionally nullify `p', then it
would be very hard to catch the cases where two deallocations are
actually a bug.
| BTW, Pascal implementations set deleted pointers to nil automatically
| ('dispose p'). I don't recall hearing any complaints about it.
Well, I don't use Pascal for production programs -- I use it only for
academic purpose (teaching) -- so I can't comment. And I don't
recall it is a requirement that `dispose p' should nullify `p'.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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 <david@tribble.com>
Date: 2000/09/26 Raw View
David R Tribble <david@tribble.com> wrote in message
>> OTOH, Nevin Liber gave a (nay, the only) convincing argument why
>> the "delete should nullify its pointer" is a dangerous thing.
Balog Pal wrote:
> You mean this example:
>
> class TMe
> {
> public:
> TMe * me;
> TMe() { me = this; }
> };
>
> void silly()
> {
> TMe * myself = new TMe;
> delete myself.me;
> }
No, I meant his example where the code originally looks something
like:
// First revision
class Foo
{
private:
Bar * m_bar; // [P]
public:
void release()
{
delete m_bar; // [A] Assumes m_bar is set to null
}
void use()
{
... *m_bar ... // [B]
}
...
};
Then along comes another programmer who changes the type of the
pointer to be a const pointer:
// Second revision
Bar *const m_bar; // [P]
Now the delete at [A] compiles silently, deleting object *m_bar
but not setting the m_bar pointer to null (because it can't).
So the second programmer has created a lurking bug that is not
evident until [B] is executed.
But this example assumes that the compiler is silent about [A].
My original suggestion proposed that a diagnostic (warning) would
be issued when deleting through const pointers, even if they are
about to go out of scope, since this is a sure sign of creating
dangling const pointers.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: pdimov@techno-link.com
Date: 2000/09/27 Raw View
In article <m3n1gxq26l.fsf@merlin.codesourcery.com>,
Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
> So, let me make some clarifications.
>
> 'Delete'ing a non null pointer (in real world programs) triggers
> (among other things) request for memory release; and I'm considering
> the problem from that point of view. Not from an academic point fo
> view -- not that that perspective is not interesting, but just because
> it focuses on purely theorical point of view and ignores practical
> considerations.
Ok, I'll try to restate my point.
When I 'delete' a pointer (assume non-shared ownership) (yes, in real
world programs,) this pointer is an 'owning pointer'. In addition to
this, no live aliases exist at this point.
I maintain an invariant on owning pointers. The invariant is that they
can be safely deleted, that is, they either point to something that was
allocated with new (and not delete'd, of course), or they are NULL.
Under the current 'delete' semantics to maintain this invariant I have
to set pointers either to NULL or to a new block of storage immediately
after 'delete' (if the pointer persists after the delete, i.e. this is
not a destructor or the pointer does not get out of scope right after
the delete.)
The new 'delete' semantics would maintain this invariant automatically.
Under these assumptions, a second delete request on an owning pointer
is not an error - because a 'delete' on an owning pointer is never an
error - this is what the invariant states.
What's so academic in that? auto_ptr does the same. So would any class
that permits explicit acquire/release.
(Yes, this means that I never delete an rvalue or a non-modifiable
lvalue; and I never 'delete this'.)
Rereading your original post, yes, delete'ing a non-null pointer is a
request for memory release. A second request to release the same block
is obviously an error. However, had the pointer been set to zero (or
another valid value according to the invariant) you simply can't issue
a second release request on that already released block.
In other words, to make the 'second delete' mistake you have to make
another mistake first (a 'first delete' mistake.) Either you don't
maintain the invariant properly, or you have a live alias.
--
Peter Dimov
Multi Media Ltd.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: comeau@panix.com (Greg Comeau)
Date: Sun, 24 Sep 2000 03:00:28 GMT Raw View
In article <39CBBEBA.3F75718D@tribble.com>,
David R Tribble <david@tribble.com> wrote:
>Please provide an example where setting a recently deleted pointer
>to null creates a bug. Otherwise, I don't believe you.
Pardon? That kind of talk is unnecessary.
Please note that I did not say that delete/delete'ing did it.
I was talking in general about pointer problems and of
nulling pointers.
What I said, or at least what I intended to say, is that
I've seen many times where the programmers swore what they
were doing was fine, just because they "did the right thing"
but nulling the pointer (see my other messages about possible
false senses of security). Most of the _real_ cases
I've seen were in C code (so if anything, they involved
malloc(), but I don't view that particularly critical per se)
and involved setting invalid memory, as a pointer, to null
(this can sometimes give the illusion that all is fine,
but clearly not). Also, I've seen folks set valid pointers
(that should remain valid) to null (this creates muliple types
of bugs).
As to delete setting a pointer to null possibly creating
a bug I've never thought about that yet. Now that you
mention it, I wonder above the following:
1) Used defined and/or class operator delete. It would seem
that this too would have to abide by the same semantics,
but I just can't go the full mile that that would always
make sense.
2) Things like shared memory, multiple threads, etc.
(C++ doesn't support these per se, but they're still indirectly
involved).
3) Multiple pointers to the same object
(I argue that if delete should null one of them, then delete
should null all of them)
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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: brangdon@cix.compulink.co.uk
Date: 2000/09/24 Raw View
pdimov@mmltd.net (Peter Dimov) wrote (abridged):
> Hmm, I don't think that it promises anything. After 'delete p'
> accessing *p is an error, regardless of whether p is automatically
> set to 0 or not.
Am I right in thinking that after "delete p", accessing p itself is an
error? Eg:
char *p = new char[2];
char *p2 = p;
delete p;
assert( p == p2 ); // Undefined behaviour?
If so, there is currently no way a conforming program can discover
whether the compiler changes p or not. It may set p to 0, or 0xdeadbeef,
or whatever, behind the scenes.
Conceptually the code is similar to:
char *p;
char *p2;
assert( p == p2 ); // Undefined behaviour.
On some hardware, address registers are checked for validity when they
are loaded rather than when they are indirected-through. Thus merely
looking at an undefined variable may cause a hardware fault. In the
delete case, the delete operation may cause previously valid memory to
become invalid.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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: 2000/09/24 Raw View
David R Tribble wrote:
>
> Andrei Alexandrescu wrote:
...
> > That's not the issue; delete could have treated const pointers and
> > rvalues different than lvalue pointers.
>
> And why would you want to delete through a const pointer anyway?
Because I declared it const, to prevent it from being changed during
it's lifetime, and now that it's lifetime is about to end, I want to
deallocate the memory, without wasting space or time creating a
temporary that zeroing delete would be free to write to. I'll grant you,
this is a pattern I've used more often in C with malloc() and free, than
in C++ with new and delete - C++ makes explicit allocation/deallocation
significantly less necessary.
...
> > The thing with delete nullifying its argument is that it promises
> > more that it can actually do...
>
> Such as? "Delete the object pointed to by a pointer, then invalidate
> the pointer." What more should it do?
Zero all of the pointers to the same piece of memory. Which it can't do.
Which it must do, to justify the sense of safety that some people
mistakenly derive from it.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/24 Raw View
Jim Hyslop <jim.hyslop@leitch.com> writes:
| In article <m3zol3rrwh.fsf@merlin.codesourcery.com>,
| Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
| [snip]
| > I guess, that is a matter of opinion. Releasing a twice a storage
| > is bug or a design error.
| I don't agree. There are design situations where a pointer can be
| released prior to the containing object being destroyed. Why is that a
^^^^^^^^^^
| design error?
I'm concerned with the *contained* object, not the containing object.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/24 Raw View
David R Tribble <david@tribble.com> writes:
| David R Tribble at david@tribble.com wrote:
| >> Some defensive programming can help in these cases (at least in your
| >> code):
| >>
| >> delete p, p = NULL; // Do this at every delete
| >>
| >> (It's a shame that 'delete' doesn't do this for you automatically.)
|
| Anders Pytte wrote:
| > I agree; however, then you could not delete const pointers:
| >
| > int main()
| > {
| > char* const data = new char[16];
| > delete data; data = 0; // rejected
| > }
|
| If the semantics of 'delete' were changed to automatically set
| deleted pointers to null, there would be a requirement that such
| a pointer must be a modifiable lvalue.
But that point of view ignores the fact that object address could be
computed and the result passed to `delete'; setting the computed
pointer to zero just gives a false sense of security.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/24 Raw View
David R Tribble <david@tribble.com> writes:
| [attributions unclear]
|
| David Tribble wrote:
| > | delete p, p = NULL; // Do this at every delete
| > |
| > | (It's a shame that 'delete' doesn't do this for you automatically.)
|
| Gabriel Dos Reis wrote:
| >> For that to happen, `delete' should require a modifiable lvalue.
|
| "Balog Pal" <pasa@lib.hu> writes:
| >| delete is a keyword, and the compiler could behave in an intuitive
| >| way. Like setting the pointer to 0 if able, and giving a warning, but
| >| continue otherwise. Or anything else, specified.
|
| Gabriel Dos Reis wrote:
| > The fact that delete is a keyword is actually irrelevant here.
| > Furtermore I won't certainly want to get noise from the compiler each
| > time I don't use a modifiable lvalue in a delete-expression.
|
| How often is that? I would wager that less than 1% of your deletes
| ever do this.
Where does your figure come from? I have it that the following
construct (or something along these lines) is common in the C++
community.
struct list_node_base {
void* data;
list_node_base* next;
};
template<typename T>
struct list_node {
void deallocate_data { delete (T*) data; }
};
Furthermore, if a program happens to release twice the same storage
then there must be something really wrong either with the program or
with the design; requiring `delete' -- in that case -- to set
automatically the pointer to NULL is just papering over the problem.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: llewelly.@@edevnull.dot.com
Date: 2000/09/25 Raw View
Barry Margolin <barmar@genuity.net> writes:
> In article <39CBC42A.947D29ED@tribble.com>,
> David R Tribble <david@tribble.com> wrote:
> >I'd go one step further and state that most of the things that the
> >compiler can do for you that you should, by all rights, be doing to
> >make your code safer, should be considered for inclusion as part of
> >the standard language semantics.
>
> Just think of how much time could have been saved if you folks had just
> used Lisp in the first place, instead of spending the past two decades
> grafting pieces of it onto C. :)
Just ask yourself who uses CLOS. :-)
(Do not take that wrong - CLOS is wonderful and expressive language -
but it is also woefully underused.)
Stroustrup discusses his reasons for choosing C as a base (see D&E,
section 2.7, pgs 43-45). Availibility was perhaps the most
important; it is likely that without backwards compatibility with C,
C++ would have been yet another wonderful language that nobody used.
There are some other aspect of Lisp that I think would have made it
undesirable as a base for a language like C++:
(0) Lisp has many good qualities, but it is not suitable for
low-level programming - and I get the impression that preserving
the ability to do low-level programming was an important to the
designers of C++.
(1) Stroustrup wanted a staticly typed language - Lisp is dynamicly
typed.
(2) Lisp was precieved as inefficient at the time. Now, please do
not send me flames or benchmarks - I got tons of the former from
Erik Naggum himself some years ago, and I have run plenty of the
latter on my own. I know that modern comon lisp implementations
generate fast code - but the decision to base C++ on C was made
in the early 1980s, when that was not the case (with the
possible exception of certain dedicated lisp machines), and when
even a small performance difference was quite important.
Now, none of the above means that Lisp would have been a poor language
to base a new multi-paradigm language on (just look at CLOS) - but
C++ was intended to be good at some things that were outside of
Lisp's domain.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/25 Raw View
"Peter Dimov" <pdimov@mmltd.net> writes:
| "Gabriel Dos Reis" <gdr@merlin.codesourcery.com> wrote in message
| news:m3zol3rrwh.fsf@merlin.codesourcery.com...
| > "Peter Dimov" <pdimov@mmltd.net> writes:
| >
| > | Only if you consider a second delete (of the same pointer, not an
| alias)
| > | an error. I don't.
| >
| > I guess, that is a matter of opinion. Releasing a twice a storage
| > is bug or a design error.
|
| What I'm trying to say is that calling 'delete' twice on the same
| pointer is not an error, not that releasing the same storage twice is
| not an error.
So, let me make some clarifications.
'Delete'ing a non null pointer (in real world programs) triggers
(among other things) request for memory release; and I'm considering
the problem from that point of view. Not from an academic point fo
view -- not that that perspective is not interesting, but just because
it focuses on purely theorical point of view and ignores practical
considerations.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/25 Raw View
David R Tribble <david@tribble.com> writes:
| Andrei Alexandrescu wrote:
| >
| > > I agree; however, then you could not delete const pointers:
| > >
| > > int main()
| > > {
| > > char* const data = new char[16];
| > > delete data; data = 0; // rejected
| > > }
| >
| > That's not the issue; delete could have treated const pointers and
| > rvalues different than lvalue pointers.
|
| And why would you want to delete through a const pointer anyway?
Why would you want to treat differently modifiable lvalue pointers and
rvalue pointers anyway?
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: 2000/09/25 Raw View
brangdon@cix.compulink.co.uk writes:
>Am I right in thinking that after "delete p", accessing p itself is an
>error? Eg:
>
> char *p = new char[2];
> char *p2 = p;
> delete p;
> assert( p == p2 ); // Undefined behaviour?
Yes, that's right. See 3.7.3.2 paragraph 4 in the C++ standard.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/25 Raw View
David R Tribble <david@tribble.com> writes:
| David R Tribble <david@tribble.com> writes:
| >| Some defensive programming can help in these cases (at least in your
| >| code):
| >|
| >| delete p, p = NULL; // Do this at every delete
| >|
| >| (It's a shame that 'delete' doesn't do this for you automatically.)
|
| Gabriel Dos Reis wrote:
| > For that to happen, `delete' should require a modifiable lvalue.
|
| More specifically, the pointer p must be modifiable (the object it
| points to is already being modified by the delete). Once the object
| pointed to by p has been deallocated, the value of p is rendered
| invalid [5.3.5#4]. Why can't the language rules state that the
| value of the (modifiable) pointer will be set to null?
Because that wouldn't really address the fondamental issue?
| Deleting the object pointed to by a non-modifiable pointer is
| probably not a very common thing to do, and probably a source of
| bugs.
Really? So somthing along the lines below is uncommon. This is news
to me.
struct list_node_base {
void* data;
list_node_base* next;
list_node_base* previous;
};
template<typename T>
struct list_node : list_node_base {
void deallocate_data()
{ delete (T*) data; }
};
[...]
| > And I have some diffculty to see why failing to do so is a shame;
| > could you elaborate?
|
| Because a common source of bugs is forgetting to set deleted pointers
| to null.
If so, then I think the shame is on the side of the programmer;
because he has the fondamental tools to hide the implemention details
behind safe constructs.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/25 Raw View
> David Tribble wrote:
> >> Some defensive programming can help in these cases (at least in your
> >> code):
> >>
> >> delete p, p = NULL; // Do this at every delete
> >>
> >> (It's a shame that 'delete' doesn't do this for you automatically.)
> michael wrote:
> > Is it also a shame that pointers aren't initialized to NULL?
>
> David Tribble responded:
> Yep. I have to do it myself explicitly in all my constructors.
>
> MyClass::MyClass(): m_ptr(NULL), ...
> { ... }
>
yes, often, but not always, required.
> and whenever I allocate an array of pointers.
>
> Type * makeThem(int n)
> {
> Type * a = new Type[n];
>
> for (int i = 0; i < n; i++)
> a[i] = NULL;
> return a;
> }
>
> Why can't C++ be a little simpler than this?
If fits in with the idea that you pay for initialization only when you need
it:
bool b; // b might not be true or false.
float f; // f might not be a valid float.
But have I got the construct for you! auto_ptr!!
1. It is default-initialized to null:
// instead of T* p = 0;
auto_ptr<T> p; // (no object is owned)
2. You can release in a single step:
// instead of delete p, p==NULL;
p.release(); // delete the owned ptr.
As others have pointed out, your idea is unbalanced in that there may be
other pointers to the object that are not reset by the delete. If this is
_not_ the case, then the strict ownership requirements that auto_ptr
expresses may well apply.
The auto_ptr will mean you only pay for the semantics if you want 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: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/09/25 Raw View
"Trevor L. Jackson, III" wrote:
> ...
> Motivated by this thread I played around a bit with compilers I have available,
> and the construct
>
> if ( this == NULL ) {
> /* complain */
> }
>
> ... produces an error of the form "unreachable code"! I suspect that assert(
> this ) may simply disappear.
>
> Let's see, does this mean we need volatile methods to convince the compiler that
> we know more about our users that it does?
>
> I'm sure I would not be able to explain this code if I encountered it without an
> explanation:
>
> Udt & Udt::operator( Udt const & rhs ) volatile
> {
> assert( this != NULL );
> /* copy Udt:: data elements */
> return *this;
> }
The declaration says that the object pointed to by "this" is volatile.
You cannot declare "this" itself to be volatile.
--
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: "Trevor L. Jackson, III" <fullmoon@aspi.net>
Date: 2000/09/22 Raw View
Fergus Henderson wrote:
> Stephen Clamage <stephen.clamage@sun.com> writes:
>
> >Checking for this==0 inside a member function will catch a null "this"
> >pointer when the function doesn't need to be invoked via the vtable,
> >AND when no pointer conversion (e.g. derived to one of multiple bases)
> >is needed
>
> ... AND when the compiler doesn't optimize the check away.
>
Motivated by this thread I played around a bit with compilers I have available,
and the construct
if ( this == NULL ) {
/* complain */
}
... produces an error of the form "unreachable code"! I suspect that assert(
this ) may simply disappear.
Let's see, does this mean we need volatile methods to convince the compiler that
we know more about our users that it does?
I'm sure I would not be able to explain this code if I encountered it without an
explanation:
Udt & Udt::operator( Udt const & rhs ) volatile
{
assert( this != NULL );
/* copy Udt:: data elements */
return *this;
}
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 2000/09/22 Raw View
In article <39C9215C.12E57A39@tribble.com>,
David R Tribble <david@tribble.com> wrote:
>David R Tribble <david@tribble.com> writes:
>>| Some defensive programming can help in these cases (at least in your
>>| code):
>>|
>>| delete p, p = NULL; // Do this at every delete
>>|
>>| (It's a shame that 'delete' doesn't do this for you automatically.)
>
>Gabriel Dos Reis wrote:
>> And I have some diffculty to see why failing to do so is a shame;
>> could you elaborate?
>
>Because a common source of bugs is forgetting to set deleted pointers
>to null. There is little reason why the compiler couldn't do it for
>you; the only requirement is, as you said, that the deleted pointer
>by a modifiable lvalue.
My experience indicates that although that is true, it's part
of a much greater experience. :) That is to say, a common source
of bugs is pointers (period). And from that, yes, some should be
set to null, but some needn't be. So to many this means over
solving a problem.
My experience is also that I have been able to find pointers bugs
yes, including null pointer bugs, in programs claiming to null
invalid pointers. My experience is also that I have been able
to find pointer bugs in programs that nulled their pointers
(the bug was elsewhere, but tended to hide itself because of this).
It's a shame that I was well paid to find those problems.
Atop of that, it was despite the kicks and screams of the
developers that it was otherwise, all dozens of them (the same
of which couldn't find the problems).
I'm not lumping you in with those folks, in fact you have my complete
respect, because I know in addition to null'ing your pointers,
you're doing other well designed, well engineered, and well thought
out things, and not just depending upon some automation or crutch.
But I think these well-things needs to be mentioned when some
syntax or semantics, sometime even seemingly trivial syntax or semantics,
is discussed.
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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: christian.bau@isltd.insignia.com (Christian Bau)
Date: 2000/09/22 Raw View
In article <39CABC3E.89486B48@aspi.net>, "Trevor L. Jackson, III"
<fullmoon@aspi.net> wrote:
> Fergus Henderson wrote:
>
> > Stephen Clamage <stephen.clamage@sun.com> writes:
> >
> > >Checking for this==0 inside a member function will catch a null "this"
> > >pointer when the function doesn't need to be invoked via the vtable,
> > >AND when no pointer conversion (e.g. derived to one of multiple bases)
> > >is needed
> >
> > ... AND when the compiler doesn't optimize the check away.
> >
>
> Motivated by this thread I played around a bit with compilers I have
available,
> and the construct
>
> if ( this == NULL ) {
> /* complain */
> }
>
> ... produces an error of the form "unreachable code"! I suspect that assert(
> this ) may simply disappear.
>
> Let's see, does this mean we need volatile methods to convince the
compiler that
> we know more about our users that it does?
You could write
volatile my_class_type_ptr volatile_this = this;
if (volatile_this == NULL) {
/* complain */
}
but there is this other thread running about the exact meaning of "volatile" :-)
assert (this != NULL) is a different situation. I would say a high quality
implementation should produce explicit code for an assert in a situation
like this, where the condition can only be FALSE if undefined behavior has
already happened, but that is quality of implementation and not required
by the language.
---
[ 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: nevin@enteract.com (Nevin Liber)
Date: 2000/09/22 Raw View
In article <39C9215C.12E57A39@tribble.com>,
David R Tribble <david@tribble.com> wrote:
>David R Tribble <david@tribble.com> writes:
>>| Some defensive programming can help in these cases (at least in your
>>| code):
>>|
>>| delete p, p = NULL; // Do this at every delete
>>|
>>| (It's a shame that 'delete' doesn't do this for you automatically.)
No, it isn't. p is (one of many) pointers to an object; it is not
(in general) part of the object (unless it happens to be a member of
that object, which is rare). It is good to keep them seperate and decoupled.
>More specifically, the pointer p must be modifiable (the object it
>points to is already being modified by the delete). Once the object
>pointed to by p has been deallocated, the value of p is rendered
>invalid [5.3.5#4]. Why can't the language rules state that the
>value of the (modifiable) pointer will be set to null?
What would you do in the following (albeit contrived, but still ought to be
legal) circumstance:
class TMe
{
public:
TMe * me;
TMe()
{
me = this;
}
};
void silly()
{
TMe * myself = new TMe;
delete myself.me;
}
>Deleting the object pointed to by a non-modifiable pointer is
>probably not a very common thing to do, and probably a source of
>bugs.
Why? While it is rare that pointers are declared const (not to be confused
with a pointer to a const object), just like it is rare to find a
non-global / non-static variable declared const, I don't know why this
would automatically be a source of bugs.
>Because a common source of bugs is forgetting to set deleted pointers
>to null.
And the people who do that also tend to forget to do NULL checks, and tend
to forget to NULL all the pointers that point to the given object, etc.
>There is little reason why the compiler couldn't do it for
>you; the only requirement is, as you said, that the deleted pointer
>by a modifiable lvalue.
My above example is one reason (and I can easily change it to make it
a situation that is hard to detect at compile time).
Don't couple objects and the pointers that point to them.
The only people who would really benefit from this are those language
lawyers who know the language well enough that they wouldn't be
forgetting to NULL the pointers when they needed to be NULLed, since
they are the only ones who know when they can count on a pointer being
NULLed and when they can't.
--
Nevin ":-)" Liber <mailto:nevin@enteract.com> (773) 961-1620
---
[ 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 <david@tribble.com>
Date: 2000/09/22 Raw View
Scott Robert Ladd wrote:
> [...] And don't believe the Java developers who claim it can't happen
> to them; I've had more trouble with people who still manage to create
> dangling references and other stupidities in Java, despite that
> language's hype about being "safer" than C++.
Please explain how you create a "dangling" reference in Java.
If by "dangling", you mean a reference that points to a non-existent
object, please explain how proper garbage collection allows such
a thing to occur. As long as there is at least one live reference
pointing to a given object, that object will never go away. (I am
willing to believe that you can create such a situation if you call
native C functions underneath which interfere with the Java GC
mechanisms, though.)
On the other hand, it is quite easy in Java to cause memory leaks
by not releasing unnecessary object references, and they continue
to hang around during the whole program execution, consuming memory
space that should have been deallocated long ago. But this is the
opposite of dangling references.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/22 Raw View
[attributions unclear]
David Tribble wrote:
> | delete p, p = NULL; // Do this at every delete
> |
> | (It's a shame that 'delete' doesn't do this for you automatically.)
Gabriel Dos Reis wrote:
>> For that to happen, `delete' should require a modifiable lvalue.
"Balog Pal" <pasa@lib.hu> writes:
>| delete is a keyword, and the compiler could behave in an intuitive
>| way. Like setting the pointer to 0 if able, and giving a warning, but
>| continue otherwise. Or anything else, specified.
Gabriel Dos Reis wrote:
> The fact that delete is a keyword is actually irrelevant here.
> Furtermore I won't certainly want to get noise from the compiler each
> time I don't use a modifiable lvalue in a delete-expression.
How often is that? I would wager that less than 1% of your deletes
ever do this. Besides, shouldn't it ring a loud bell when you
try to create a dangling const pointer?
But if you must, the workaround is trivial:
T *const p = ...;
...
delete const_cast<T*>(p);
// p is now dangling
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/22 Raw View
<kanze@gabi-soft.de> wrote:
>> The problem is that customers who call member functions with null
>> pointers will also call them with other invalid pointers (freed
>> memory, etc.). Checking for null here really won't avoid the calls
>> from angry but culpable customers.
Barry Margolin wrote:
> It will catch some, perhaps many, of them. That's better than
> nothing.
>
> Why is it that people think that solutions should not be attempted
> unless they're perfect?
Especially if the cost is negligible.
I'd go one step further and state that most of the things that the
compiler can do for you that you should, by all rights, be doing to
make your code safer, should be considered for inclusion as part of
the standard language semantics.
--
"The Star Wars defense system is flawed; what if one ICBM gets
through the barrier?"
"Good point; I guess we should stick with the system we already
have."
--
"The Clipper encryption chip allows the government to eavesdrop
on your supposedly private cell phone conversations; it's an
evil technology just waiting to be abused."
"Good point; I guess we should stick with the system we already
have."
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/22 Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote
>> Setting p to zero makes the error (slightly) more easily detectable.
>> (And a second 'delete' harmless.)
David Abrahams wrote:
> So it makes one error (a dereference through p) slightly more
> detectable*, but it completely hides another kind of error (a second
> delete). In this case I think the cure is far worse than the disease.
So I take it this is an argument against ever setting deleted pointers
to null, even explicitly?
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 Abrahams" <abrahams@mediaone.net>
Date: 2000/09/23 Raw View
"David R Tribble" <david@tribble.com> wrote in message
news:39CBC7B0.A886FF8@tribble.com...
> "Peter Dimov" <pdimov@mmltd.net> wrote
> >> Setting p to zero makes the error (slightly) more easily detectable.
> >> (And a second 'delete' harmless.)
>
> David Abrahams wrote:
> > So it makes one error (a dereference through p) slightly more
> > detectable*, but it completely hides another kind of error (a second
> > delete). In this case I think the cure is far worse than the disease.
>
> So I take it this is an argument against ever setting deleted pointers
> to null, even explicitly?
Not at all. It is an argument against automatically setting all deleted
pointers to null automatically. In debug builds at least, we should write
code that exposes unintentional, careless programming. If the code crashes
or asserts in a debug build we are forced to deal with a problem or mistaken
assumption before it creeps into a shipping build and causes worse damage
downstream.
It is arguable that such a behavior is desirable in a shipping build, and
how much resiliency to such errors we wish to deliver in a shipping build is
a policy choice worthy of careful consideration. You'll often find, however,
that such ad-hoc protections against programming errors are really just an
unneccessary efficiency hit if debug builds have been tested with the
opposite policy.
I would suggest in debug builds, you consider "delete p, p = <invalid
non-null pointer>"
Then in shipping builds, you may choose "delete p, p = 0", but you probably
won't need it.
Ciao,
Dave
---
[ 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 <david@tribble.com>
Date: 2000/09/23 Raw View
David R Tribble <david@tribble.com> wrote:
>+ delete p, p = NULL; // Do this at every delete
>+
>+ (It's a shame that 'delete' doesn't do this for you automatically.)
Phil Edwards wrote:
> I prefer
>
> delete p [,;] p = 0xDEADBEEF;
>
> with a cast for the hexidecimal constant as needed. Null pointers can
> be anywhere, but dead cow pointers only happen in a few places (my
> code, a few debugging libraries I know of, and some kernel routines).
(Assuming that 0xDEADBEEF is an invalid address on your system.)
This fine, in that p no longer points to a valid object, by virtue
of containing an invalid pointer value. But the same is true of
any null pointer, which doesn't point to any valid object (by
definition). Besides, it's more intuitive to check a that a
pointer is null (to see if it points to an object or not) than
for some other arbitrary value.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/23 Raw View
Andrei Alexandrescu wrote:
>
> > I agree; however, then you could not delete const pointers:
> >
> > int main()
> > {
> > char* const data = new char[16];
> > delete data; data = 0; // rejected
> > }
>
> That's not the issue; delete could have treated const pointers and
> rvalues different than lvalue pointers.
And why would you want to delete through a const pointer anyway?
You'd end up with an unchangeable dangling pointer. Besides:
char *const data = ...;
...
char * p = data;
delete p, p = NULL; // delete the object
// now data is invalid!
> The thing with delete nullifying its argument is that it promises
> more that it can actually do...
Such as? "Delete the object pointed to by a pointer, then invalidate
the pointer." What more should it do?
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/23 Raw View
David Tribble <david@tribble.com> wrote:
>> | delete p, p = NULL; // Do this at every delete
>> |
>> | (It's a shame that 'delete' doesn't do this for you automatically.)
Balog Pal <pasa@lib.hu> wrote:
>> [...] the intent is clear, such behavior
>> on part of delete would likely help catching bugs. Having a null
>> value in a pointer will probably explode the program immediately and
>> consistently on attempt to use it, but doing so with a value pointing
>> to a recently deleted object tends to work through the test period,
>> and end up in release code.
Greg Comeau wrote:
> [...] it also means in some cases that doing it (in general,
> not necessarily with delete) can introduce a bug, which definitely
> conflicts with helping to catch bugs :)!, a double jeopardy if ever
> there was one.
I fail to see how invalidating a deleted pointer can introduce new
bugs into any program. (I can see how failing to invalidate such
a pointer introduces bugs, though.)
Please provide an example where setting a recently deleted pointer
to null creates a bug. Otherwise, I don't believe you.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/23 Raw View
David Tribble wrote:
>> Some defensive programming can help in these cases (at least in your
>> code):
>>
>> delete p, p = NULL; // Do this at every delete
>>
>> (It's a shame that 'delete' doesn't do this for you automatically.)
michael wrote:
> Is it also a shame that pointers aren't initialized to NULL?
Yep. I have to do it myself explicitly in all my constructors.
MyClass::MyClass(): m_ptr(NULL), ...
{ ... }
and whenever I allocate an array of pointers.
Type * makeThem(int n)
{
Type * a = new Type[n];
for (int i = 0; i < n; i++)
a[i] = NULL;
return a;
}
Why can't C++ be a little simpler than this?
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: Barry Margolin <barmar@genuity.net>
Date: 2000/09/23 Raw View
In article <39CBC42A.947D29ED@tribble.com>,
David R Tribble <david@tribble.com> wrote:
>I'd go one step further and state that most of the things that the
>compiler can do for you that you should, by all rights, be doing to
>make your code safer, should be considered for inclusion as part of
>the standard language semantics.
Just think of how much time could have been saved if you folks had just
used Lisp in the first place, instead of spending the past two decades
grafting pieces of it onto C. :)
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: nevin@enteract.com (Nevin Liber)
Date: 2000/09/23 Raw View
In article <zHVw5.3$Mg1.102@burlma1-snr2>,
Barry Margolin <barmar@genuity.net> wrote:
>Why is it that people think that solutions should not be attempted unless
>they're perfect?
I'm not against partial solutions; I'm against BAD solutions that cause more
subtle bugs than the obvious ones that they are purporting to fix.
If this feature were added, declaring/not declaring something const would
now change the run-time semantics of a C++ program instead of just the
compile-time semantics; this is not a good idea.
For instance, suppose you have the following class which Dr. Language Lawyer
wrote:
class TOtherClass
{
private:
TClass * theClass;
// ...
public:
TOtherClass()
{
class = new TClass;
}
~TOtherClass()
{
delete theClass;
// other cleanup
}
void DeleteTheClass()
{
delete theClass;
}
bool IsTheClassSet() const
{
return NULL != theClass;
}
// ...
};
Dr. Language Lawyer, clever woman that she is, knows that class will be set
to NULL automatically by the new and improved C++ being proposed here, so
she never explicitly sets them to NULL.
Mr. Const Cop comes along and is tasked with maintaining the code. He looks
at TOtherClass::DeleteTheClass() and notices that it doesn't seem to modify
any of the non-static member variables of TOtherClass. Sounds like a good
candidate to become a const member function, doesn't it? Now it looks like:
void TOtherClass::DeleteTheClass() const
{
delete theClass;
}
No compiler warnings. Not a peep.
Mr. Const Cop is satisfied in the knowledge of improving the code and a
job well done.
Even assuming we survive the obvious bug:
void WhatShouldIDo()
{
TOtherClass otherClass;
otherClass.DeleteTheClass();
if (otherClass.IsTheClassSet()) {
DestroyTheWorld()
} else {
MakeAPopTart();
}
}
the code now has a subtle double delete bug. All because of this seemingly
innocuous proposal, which has the subtle effect that adding/removing a const
declaration subtly changes the run-time semantics of the code in a way that,
even at a minimum, is not warned about at compile time.
Like I said, this is not a good idea...
--
Nevin ":-)" Liber <mailto:nevin@enteract.com> (773) 961-1620
---
[ 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: 2000/09/23 Raw View
David R Tribble wrote:
...
> Gabriel Dos Reis wrote:
...
> > Furtermore I won't certainly want to get noise from the compiler each
> > time I don't use a modifiable lvalue in a delete-expression.
>
> How often is that? I would wager that less than 1% of your deletes
> ever do this. Besides, shouldn't it ring a loud bell when you
> try to create a dangling const pointer?
In general, when I'm do things like that, the const pointer is going out
of scope immediately after the delete; the last thing I want is for
'delete' to waste time setting it to 0. Your const_cast<>() 'solution'
only makes it worse: a temporary pointer is created, set to 0, and is
then released.
---
[ 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: Gabriel Dos Reis <gdr@merlin.codesourcery.com>
Date: 2000/09/20 Raw View
"Peter Dimov" <pdimov@mmltd.net> writes:
| "David Abrahams" <abrahams@mediaone.net> wrote in message
| news:udyx5.7130$tn.91231@typhoon.ne.mediaone.net...
| >
| > "Peter Dimov" <pdimov@mmltd.net> wrote in message
| > news:8q5910$ptp$1@weber.techno-link.com...
| >
| > > Setting p to zero makes the error (slightly) more easily detectable.
| > > (And a second 'delete' harmless.)
| >
| > So it makes one error (a dereference through p) slightly more
| detectable*,
| > but it completely hides another kind of error (a second delete). In
| this
| > case I think the cure is far worse than the disease.
|
| Only if you consider a second delete (of the same pointer, not an alias)
| an error. I don't.
I guess, that is a matter of opinion. Releasing a twice a storage
is bug or a design error.
Sure, one can invent any academic, contrived example to illustrate a
purely rhetorical point -- we are talking about C++, after all. The
fact remains: from a software methodology point of view, releasing
twice a storage is a sign of error either in the program or in the
design.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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 <david@tribble.com>
Date: 2000/09/20 Raw View
David R Tribble at david@tribble.com wrote:
>> Some defensive programming can help in these cases (at least in your
>> code):
>>
>> delete p, p = NULL; // Do this at every delete
>>
>> (It's a shame that 'delete' doesn't do this for you automatically.)
Anders Pytte wrote:
> I agree; however, then you could not delete const pointers:
>
> int main()
> {
> char* const data = new char[16];
> delete data; data = 0; // rejected
> }
If the semantics of 'delete' were changed to automatically set
deleted pointers to null, there would be a requirement that such
a pointer must be a modifiable lvalue. We could enhance the rules
to cover non-modifiable pointer values, causing a warning to be
issued (but the delete would still happen). This reflects the
problem of creating a dangling const pointer.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/21 Raw View
David R Tribble <david@tribble.com> writes:
>| Some defensive programming can help in these cases (at least in your
>| code):
>|
>| delete p, p = NULL; // Do this at every delete
>|
>| (It's a shame that 'delete' doesn't do this for you automatically.)
Gabriel Dos Reis wrote:
> For that to happen, `delete' should require a modifiable lvalue.
More specifically, the pointer p must be modifiable (the object it
points to is already being modified by the delete). Once the object
pointed to by p has been deallocated, the value of p is rendered
invalid [5.3.5#4]. Why can't the language rules state that the
value of the (modifiable) pointer will be set to null?
Deleting the object pointed to by a non-modifiable pointer is
probably not a very common thing to do, and probably a source of
bugs.
Type *const p = new Type();
...
delete p;
// p is no longer a valid pointer
p = NULL; // Error, p is const
> And I have some diffculty to see why failing to do so is a shame;
> could you elaborate?
Because a common source of bugs is forgetting to set deleted pointers
to null. There is little reason why the compiler couldn't do it for
you; the only requirement is, as you said, that the deleted pointer
by a modifiable lvalue.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: "Peter Dimov" <pdimov@mmltd.net>
Date: 2000/09/21 Raw View
"Gabriel Dos Reis" <gdr@merlin.codesourcery.com> wrote in message
news:m3zol3rrwh.fsf@merlin.codesourcery.com...
> "Peter Dimov" <pdimov@mmltd.net> writes:
>
> | Only if you consider a second delete (of the same pointer, not an
alias)
> | an error. I don't.
>
> I guess, that is a matter of opinion. Releasing a twice a storage
> is bug or a design error.
What I'm trying to say is that calling 'delete' twice on the same
pointer is not an error, not that releasing the same storage twice is
not an error.
int * p = new int;
delete p; p = new int;
delete p; // second delete on the same pointer
Similarly:
int * p = 0;
delete p; // first delete, is this an error?
delete p; // second delete, not an error
p = new int;
delete p; p = 0;
delete p; // second delete, not an error
The idiom I'm talking about is that an owning pointer has the property
that a delete can safely be applied to it - as an invariant.
Therefore, several consecutive delete's are not an error - provided that
the invariant is preserved.
Of course, the current delete does not preserve this invariant, but a
hypothetical zero-setting delete would.
--
Peter Dimov
Multi Media Ltd.
---
[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: Fri, 22 Sep 2000 01:17:54 GMT Raw View
In article <m3zol3rrwh.fsf@merlin.codesourcery.com>,
Gabriel Dos Reis <gdr@merlin.codesourcery.com> wrote:
[snip]
> I guess, that is a matter of opinion. Releasing a twice a storage
> is bug or a design error.
I don't agree. There are design situations where a pointer can be
released prior to the containing object being destroyed. Why is that a
design error?
> Sure, one can invent any academic, contrived example to illustrate a
> purely rhetorical point -- we are talking about C++, after all. The
> fact remains: from a software methodology point of view, releasing
> twice a storage is a sign of error either in the program or in the
> design.
Please elaborate - *why* is this a design error? I have seen people
expound this notion many times, but nobody has explained why.
Quite frankly, I don't see it as an error. I have a real-life,
non-trivial program here that can set a pointer to null before the end
of the lifetime of the containing object. Exactly how is that a design
error?
--
Jim
This message was posted using plain text only. Any hyperlinks you may
see were added by other parties without my permission.
I do not endorse any products or services that may be hyperlinked to
this message.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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" <serrano@ozemail.com.au>
Date: 2000/09/18 Raw View
> Some defensive programming can help in these cases (at least in your
> code):
>
> delete p, p = NULL; // Do this at every delete
>
> (It's a shame that 'delete' doesn't do this for you automatically.)
Is it also a shame that pointers aren't initialized to NULL?
---
[ 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: 2000/09/18 Raw View
Stephen Clamage <stephen.clamage@sun.com> writes:
>Checking for this==0 inside a member function will catch a null "this"
>pointer when the function doesn't need to be invoked via the vtable,
>AND when no pointer conversion (e.g. derived to one of multiple bases)
>is needed
... AND when the compiler doesn't optimize the check away.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: llewelly.@@edevnull.dot.com
Date: 2000/09/18 Raw View
comeau@panix.com (Greg Comeau) writes:
> In article <kpdw5.45284$98.4185210@typhoon.tampabay.rr.com>,
> Scott Robert Ladd <sladd@tampabay.rr.com> wrote:
> >> Why would the compiler bother with a vtable lookup in the above situation?
> >
> >Some compilers *will* make a direct call to a virtual method, skipping the
> >vtable lookup if the precise type of the target object is known.
>
> Do you know of a _compiler_ which doesn't do this?
hm...
struct Base {virtual void bar();};
struct Derived:Base {virtual void bar();};
void Base::bar(){}
void Derived::bar(){}
int main()
{
Base* bp=new Derived;
bp->bar();
delete bp;
}
I have seen compilers that fail to use data flow analysis to eliminate
the virtual method lookup in cases like the above. gcc 2.95.2, sun
4.2, and borland 5.0 are among them. (Note that all 3 of these
compilers use data-flow analysis to perform other optimizations.)
(Note that borland 5.0 and sun 4.2 are not current versions of
either of those compilers, but I do not have experience with more
recent versions.)
---
[ 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 Robert Ladd" <scott@coyotegulch.com>
Date: 2000/09/18 Raw View
"David R Tribble" <david@tribble.com> wrote...
> Unfortunately, checking for null only solves part of the problem.
> You can't check that a pointer points to a deleted/unallocated
> object, or can't check (in general) that a pointer contains an
> invalid (unmapped virtual) address. Passing around dangling pointers
> to long-since deleted objects is probably more common than passing
> null pointers around.
Agreed on all points. Which is why the overhead of "if (this == NULL)" is
unjustifiable; it only catches one of many possible pointer problems.
Dangling pointers, bad indexing, stupid pointer math... all those can bite
us.Which all begs the question: *Can* you prevent people from being stupid?
Lord knows, this is a big issue for us; we're wrapping a portable C++ class
library in Microsoft's COM; COM loves pointers, and we're weighing the level
of paranoia we need to implement. Our "toolkit" is designed for vertical
market OEMs, where the software runs in a batch mode, processing billions of
bytes of data a day. We have several dozen customers, many of whom use
Visual Basic to wrap our library.
For class interfaces, I avoid pointers like the plague -- but there really
isn't any way I can see to prevent the use of "bad" this pointers, or
references to invalid objects, or any of the other myriad things programmers
can throw at me. We're doing a lot of the defensive stuff, like the below...
but I just can't see checking *every* (or even most) references and "this"
pointers for NULL.
> Some defensive programming can help in these cases (at least in your
> code):
>
> delete p, p = NULL; // Do this at every delete
>
> (It's a shame that 'delete' doesn't do this for you automatically.)
Agreed on delete; is there any reason *why* the ISO standard does not
mandate delete to do the above?
** Scott Robert Ladd
* http://www.coyotegulch.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: "Peter Dimov" <pdimov@mmltd.net>
Date: 2000/09/18 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> wrote in message
news:ss7v5m98h3t113@news.supernews.com...
> > I agree; however, then you could not delete const pointers:
> >
> > int main()
> > {
> > char* const data = new char[16];
> > delete data; data = 0; // rejected
> > }
This may be considered a good thing, if you subscribe to the idea that
'delete p' should set p to zero.
'delete p', while physically const, is logically a non-const operation
on p, because it modifies its value from 'valid' to 'invalid - undefined
behavior ahead if you access it.'
> The thing with delete nullifying its argument is that it promises more
that
> it can actually do...
Hmm, I don't think that it promises anything. After 'delete p' accessing
*p is an error, regardless of whether p is automatically set to 0 or
not.
Setting p to zero makes the error (slightly) more easily detectable.
(And a second 'delete' harmless.)
--
Peter Dimov
Multi Media Ltd.
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/09/18 Raw View
"Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
news:m3aed8fku3.fsf@merlin.codesourcery.com...
> Furtermore I won't certainly want to get noise from the compiler each
> time I don't use a modifiable lvalue in a delete-expression.
This is a moot point. The compiler could treat lvalues and rvalues
differently.
On the other hand (I have five fingers) I agree that having delete nullify
its argument - when it's an lvalue - is not going to save Willy.
Andrei
---
[ 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 Robert Ladd" <scottrobertladd@hotmail.com>
Date: 2000/09/18 Raw View
"Greg Comeau" <comeau@panix.com> wrote...
> My experience is that although this may be so for some simple programs,
> that the general end result is usually a false sense of security
> especially given the attitude of many programmers.'
Ah, a man who can hit a nail squarely upon its head.
I don't think you can idiot-proof programming. A good analogy would be a
door with a lock; it makes sense to have a good solid lock, keeping "honest
people honest" -- but since any professional burglar can pick almost any
lock, putting on two or three locks is merely an inconvenience, not a
deterrent.
In the case of checking "this" for NULL, it seems to be putting extraneous
locks on the door. If someone is likely to call a method via NULL, they are
also likely to express other annoying habits that won't even occur to me. I
don't think we can enumerate all the possible contortions that programmers
can engage in...
If a language does too much thinking for a programmer, the programmer loses
their edge; they stop worrying about the details, and in software, the
details are everything.
Or, as my co-worker puts it: "Visual Basic makes you weak."
** Scott Robert Ladd
* http://www.coyotegulch.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: "Marco Manfredini" <marco@taristhe.refrigerator.magnets.de>
Date: 2000/09/18 Raw View
"Scott Robert Ladd" <scott@coyotegulch.com> wrote in message
news:nP9x5.60500$98.5622540@typhoon.tampabay.rr.com...
> "David R Tribble" <david@tribble.com> wrote...
> > Unfortunately, checking for null only solves part of the problem.
> > You can't check that a pointer points to a deleted/unallocated
> > object, or can't check (in general) that a pointer contains an
> > invalid (unmapped virtual) address. Passing around dangling pointers
> > to long-since deleted objects is probably more common than passing
> > null pointers around.
>
> Agreed on all points. Which is why the overhead of "if (this == NULL)" is
> unjustifiable; it only catches one of many possible pointer problems.
> Dangling pointers, bad indexing, stupid pointer math... all those can bite
> us.Which all begs the question: *Can* you prevent people from being
stupid?
>
I think the compilers should have a "strict" mode which compilers all
operations with runtime checks for undefined behaviour (where possible, like
the invalid usage of NULL pointers), that throw if the program is about to
run into such an undefined state.
The Standard already says that these and that operations are undefined if
used with these and that arguments, so why can't the runtime tell me? Why do
I have to check everything by hand?
And if the programm passes all tests, I am still free to select a more
reckless evaluation mode, if speed is a bigger requirement than security..
>
> > Some defensive programming can help in these cases (at least in your
> > code):
> >
> > delete p, p = NULL; // Do this at every delete
> >
> > (It's a shame that 'delete' doesn't do this for you automatically.)
>
> Agreed on delete; is there any reason *why* the ISO standard does not
> mandate delete to do the above?
>
Is it "You don't pay for what you don't want" again? I can't think of that,
since setting p to
NULL costs nothing compared to what happens in delete. Or is it "don't give
a false sense of security", since setting p to NULL does not NULL the
aliases?
But maybe it's "don't put into the language, what can be done with the
language (or something)":
template<class T>
void dispose(T * &t)
{
if (t)
{
delete t;
t=NULL;
}
}
--
Marco
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/18 Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
| "Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
| news:m3aed8fku3.fsf@merlin.codesourcery.com...
| > Furtermore I won't certainly want to get noise from the compiler each
| > time I don't use a modifiable lvalue in a delete-expression.
|
| This is a moot point.
Takne out of context, probably.
But I don't know how much value has a sentence taken out of context.
| The compiler could treat lvalues and rvalues differently.
I was responding to this:
> delete is a keyword, and the compiler could behave in an intuitive way. Like
> setting the pointer to 0 if able, and giving a warning, but continue
> otherwise. Or anything else, specified.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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.glassborow@ntlworld.com>
Date: 2000/09/18 Raw View
In article <39c64cb6@news.isb.net>, Marco Manfredini <marco@taristhe.ref
rigerator.magnets.de> writes
>Is it "You don't pay for what you don't want" again? I can't think of
>that, since setting p to NULL costs nothing compared to what happens in
>delete. Or is it "don't give a false sense of security", since setting p
>to NULL does not NULL the aliases? But maybe it's "don't put into the
>language, what can be done with the language (or something)":
As currently specified, delete requires the address (pointer value) of
the dynamic object, it does not require the address of a piece of
storage which contains this address. What people who want delete to
reset the pointer want is based on a common novice mistake. Consider:
void foo1(int * i){ i = new int[10];}
void foo2(int * & i){i = new int[10];}
int main(){
int * ptr1=0, ptr2=0;
foo1(ptr1);
foo2(ptr2);
};
Now what are the values of ptr1 and ptr2 just before main returns?
Whether you have the value stored or a pointer to the storage is rather
important.
Francis Glassborow 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: James Kuyper <kuyper@wizard.net>
Date: 2000/09/19 Raw View
Barry Margolin wrote:
>
> In article <86og1ozcpb.fsf@gabi-soft.de>, <kanze@gabi-soft.de> wrote:
> >The problem is that customers who call member functions with null
> >pointers will also call them with other invalid pointers (freed memory,
> >etc.). Checking for null here really won't avoid the calls from angry
> >but culpable customers.
>
> It will catch some, perhaps many, of them. That's better than nothing.
>
> Why is it that people think that solutions should not be attempted unless
> they're perfect?
I don't know. By the same logic, one could argue that one shouldn't wear
a hard hat at a construction site, because it gives you a false sense of
security: there are so many bad things that can happen that the hard hat
won't protect you against.
I think that checking "&reference==NULL" or "this==NULL" is excessive.
Checking the value returned by the "new" is absolutely pointless (unless
you specify the nothow version). However, checking ordinary pointers for
null values seems entirely appropriate to me. Sure, there's lots of
other invalid values, but null values are the only invalid values that
you can actually test with portable code, and they're one of the most
common types of invalid pointer value. Pointers to deallocated memory,
or beyond the ends of allocated memory are the other two common types,
but there's no portable way to test against either of those
possibilities.
---
[ 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 Abrahams" <abrahams@mediaone.net>
Date: 2000/09/19 Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:8q5910$ptp$1@weber.techno-link.com...
> Setting p to zero makes the error (slightly) more easily detectable.
> (And a second 'delete' harmless.)
So it makes one error (a dereference through p) slightly more detectable*,
but it completely hides another kind of error (a second delete). In this
case I think the cure is far worse than the disease.
-Dave
*unless you're dereferencing an offset which doesn't cause a crash
---
[ 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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/09/19 Raw View
"Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
news:m3ya0pzjdr.fsf@merlin.codesourcery.com...
> "Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
>
> | "Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
> | news:m3aed8fku3.fsf@merlin.codesourcery.com...
> | > Furtermore I won't certainly want to get noise from the compiler each
> | > time I don't use a modifiable lvalue in a delete-expression.
> |
> | This is a moot point.
>
> Takne out of context, probably.
>
> But I don't know how much value has a sentence taken out of context.
>
> | The compiler could treat lvalues and rvalues differently.
>
> I was responding to this:
>
> > delete is a keyword, and the compiler could behave in an intuitive way.
Like
> > setting the pointer to 0 if able, and giving a warning, but continue
> > otherwise. Or anything else, specified.
I guess I'm being dense, case in which I apologize.
I sustained, just like the poster quoted right above, that the compiler
might treat lvalues and rvalues differently. I mean, the compiler, after
delete, could store zero in an lvalue and do nothing for an rvalue.
This possible behavior moots your point about the noise that the compiler
would make if you didn't use a modifiable lvalue. That's all what I was
trying to say.
Please note that I'm not advocating that this is a good solution; I was just
trying to make it clear that the problem you mention would be easy to
mitigate.
Andrei
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 2000/09/19 Raw View
In article <Cupx5.7$V66.5181@typhoon.tampabay.rr.com>,
Scott Robert Ladd <scottrobertladd@hotmail.com> wrote:
>"Greg Comeau" <comeau@panix.com> wrote...
>> My experience is that although this may be so for some simple programs,
>> that the general end result is usually a false sense of security
>> especially given the attitude of many programmers.'
>
>Ah, a man who can hit a nail squarely upon its head.
>
>I don't think you can idiot-proof programming. A good analogy would be a
>door with a lock; it makes sense to have a good solid lock, keeping "honest
>people honest" -- but since any professional burglar can pick almost any
>lock, putting on two or three locks is merely an inconvenience, not a
>deterrent.
Especially when the window next to the door is wide open :)
>In the case of checking "this" for NULL, it seems to be putting extraneous
>locks on the door. If someone is likely to call a method via NULL, they are
>also likely to express other annoying habits that won't even occur to me. I
>don't think we can enumerate all the possible contortions that programmers
>can engage in...
>
>If a language does too much thinking for a programmer, the programmer loses
>their edge; they stop worrying about the details, and in software, the
>details are everything.
>
>Or, as my co-worker puts it: "Visual Basic makes you weak."
Yup.
BTW, in an earlier post I think you mentioned some of this
not being discussed in popular texts. Although not directly
on this subject, I seem to recall Stroustrup's 3rd ed's
discussion about exception handling pragmatics to be as applicable
here as it is there.
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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: Barry Margolin <barmar@genuity.net>
Date: 2000/09/19 Raw View
In article <39C6A977.9B2609B1@wizard.net>,
James Kuyper <kuyper@wizard.net> wrote:
>I think that checking "&reference==NULL" or "this==NULL" is excessive.
I agree that checking "&reference" is excessive. The programmer generally
has to go out of his way to create a null reference, and the point of
checks like this is to catch mistakes, not malicious code. Checking "this"
isn't quite the same, since it's not too hard to call a member function
through a null pointer when the class can be determined statically; I think
this is a matter of style.
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: comeau@panix.com (Greg Comeau)
Date: 2000/09/19 Raw View
In article <39C6A977.9B2609B1@wizard.net>,
James Kuyper <kuyper@wizard.net> wrote:
>Barry Margolin wrote:
>> Why is it that people think that solutions should not be attempted unless
>> they're perfect?
>
>I don't know. By the same logic, one could argue that one shouldn't wear
>a hard hat at a construction site, because it gives you a false sense of
>security: there are so many bad things that can happen that the hard hat
>won't protect you against.
I don't think folks are saying to never check for the null pointer,
or never to set a pointer to null, just to do so judiciously.
Also, I think the spirit of your analogy is a good one,
but the reality is that although I can't imagine a ctor :)
worker thinking a hard hat is sufficient protection,
I know (not opinion!) many programmers who think that just
0'ing the pointer after delete is. And _that's_ the false sense
of security. The problem isn't the limitation of different
kinds of invalid pointer etc. per se, the problem is in not
even recognizing the limitation exists. The hard hat'er knowns
a beam might still crack them, or that it won't help them
when driving a truck into freshly poured concrete, but many
programmers are not as "street smart" in similar programmer
contexts. So, IMO "put a hard hat on" shouldn't be a similar
guideline to "null delete'd pointers", unless of course
you are fixing a pointer bug in the automation software at
a construction site :)
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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: Barry Margolin <barmar@genuity.net>
Date: 2000/09/19 Raw View
In article <ssdd5u4ago8d9f@news.supernews.com>,
Andrei Alexandrescu <andrewalex@hotmail.com> wrote:
>"Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
>news:m3ya0pzjdr.fsf@merlin.codesourcery.com...
>> "Andrei Alexandrescu" <andrewalex@hotmail.com> writes:
>>
>> | "Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
>> | news:m3aed8fku3.fsf@merlin.codesourcery.com...
>> | > Furtermore I won't certainly want to get noise from the compiler each
>> | > time I don't use a modifiable lvalue in a delete-expression.
>> |
>> | This is a moot point.
>>
>> Takne out of context, probably.
>>
>> But I don't know how much value has a sentence taken out of context.
>>
>> | The compiler could treat lvalues and rvalues differently.
>>
>> I was responding to this:
>>
>> > delete is a keyword, and the compiler could behave in an intuitive way.
>Like
>> > setting the pointer to 0 if able, and giving a warning, but continue
>> > otherwise. Or anything else, specified.
>
>I guess I'm being dense, case in which I apologize.
>
>I sustained, just like the poster quoted right above, that the compiler
>might treat lvalues and rvalues differently. I mean, the compiler, after
>delete, could store zero in an lvalue and do nothing for an rvalue.
He was responding to a post that said something like "giving a warning
otherwise", referring to the cases where it couldn't store a 0. I think
that's what he meant about not wanting to get noise from the compiler.
If it null'ed the pointer when it can and did nothing silently in other
cases, I suspect that would satisfy him.
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: "Peter Dimov" <pdimov@mmltd.net>
Date: 2000/09/20 Raw View
"David Abrahams" <abrahams@mediaone.net> wrote in message
news:udyx5.7130$tn.91231@typhoon.ne.mediaone.net...
>
> "Peter Dimov" <pdimov@mmltd.net> wrote in message
> news:8q5910$ptp$1@weber.techno-link.com...
>
> > Setting p to zero makes the error (slightly) more easily detectable.
> > (And a second 'delete' harmless.)
>
> So it makes one error (a dereference through p) slightly more
detectable*,
> but it completely hides another kind of error (a second delete). In
this
> case I think the cure is far worse than the disease.
Only if you consider a second delete (of the same pointer, not an alias)
an error. I don't. Consider (illustration only):
class X
{
public:
X(): p(0) {}
explicit X(int i): p(new int(i)) {}
~X() { delete p; }
void acquire(int i) { int * t = new int(i); std::swap(p, t); delete
t; }
void release() { delete p; p = 0; }
private:
int * p;
X(X const &);
X& operator==(X const &);
};
The idea is that an 'owning' pointer has two and only two states, NULL
and non-NULL obtained via new.
The requirement that delete works on NULLs supports this line of
thought - in both cases the pointer can be safely deleted.
Not that anybody should use 'delete' at all, mind you. :) That's what
smart pointers and std::vector are for. The discussion is purely
theoretical.
--
Peter Dimov
Multi Media Ltd.
---
[ 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: pedwards@dmapub.dma.org (Phil Edwards)
Date: 2000/09/16 Raw View
David R Tribble <david@tribble.com> wrote:
+
+ delete p, p = NULL; // Do this at every delete
+
+ (It's a shame that 'delete' doesn't do this for you automatically.)
I prefer
delete p [,;] p = 0xDEADBEEF;
with a cast for the hexidecimal constant as needed. Null pointers can
be anywhere, but dead cow pointers only happen in a few places (my code,
a few debugging libraries I know of, and some kernel routines).
Phil
--
pedwards at disaster dot jaj dot com | pme at sources dot redhat dot com
devphil at several other less interesting addresses in various dot domains
The gods do not protect fools. Fools are protected by more capable fools.
---
[ 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.de
Date: 2000/09/16 Raw View
fjh@cs.mu.OZ.AU (Fergus Henderson) writes:
|> A good debugging C++ implementation should provide a way to perform
|> such checks automatically. So if you have a good debugging C++
|> implementation, they're not needed. (Not that I know of any such
|> implementations...)
The GreenHills compiler will generate null pointer checks if you set the
right options. (Or at least it would -- it's been some time since I
last used it.)
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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.de
Date: 2000/09/16 Raw View
Ron Natalie <ron@sensor.com> writes:
|> Scott Robert Ladd wrote:
|> > I recently encounterd a commercial class library that includes
|> > what appeared to be odd and useless code:
|> > void C::M(const int & ref)
|> > {
|> > if (!this)
|> > throw ...;
|> Yep, you've learned rule #1 about undefined behavior, the program
|> may continue normally and get ill a significant distance from the
|> point of infraction. A benefit of these checks is that it brings
|> about the failure quicker. Generally, I'd put these in using assert
|> macros. I'm sure the library provider found it easier to puke in a
|> defined way than to have the code coredump with a stack trace
|> pointing into his library (and angry, even if culpable, customers
|> griping about bugs in his code).
The problem is that customers who call member functions with null
pointers will also call them with other invalid pointers (freed memory,
etc.). Checking for null here really won't avoid the calls from angry
but culpable customers.
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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: comeau@panix.com (Greg Comeau)
Date: Sun, 17 Sep 2000 04:36:19 GMT Raw View
In article <kpdw5.45284$98.4185210@typhoon.tampabay.rr.com>,
Scott Robert Ladd <sladd@tampabay.rr.com> wrote:
>> Why would the compiler bother with a vtable lookup in the above situation?
>
>Some compilers *will* make a direct call to a virtual method, skipping the
>vtable lookup if the precise type of the target object is known.
Do you know of a _compiler_ which doesn't do this?
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Sun, 17 Sep 2000 04:37:20 GMT Raw View
> I agree; however, then you could not delete const pointers:
>
> int main()
> {
> char* const data = new char[16];
> delete data; data = 0; // rejected
> }
That's not the issue; delete could have treated const pointers and rvalues
different than lvalue pointers.
The thing with delete nullifying its argument is that it promises more that
it can actually do...
Andrei
---
[ 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: comeau@panix.com (Greg Comeau)
Date: Sun, 17 Sep 2000 04:37:48 GMT Raw View
In article <000001c01f56$c33ae800$e90e38c3@bpnt>,
Balog Pal <pasa@lib.hu> wrote:
>"Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
>> | delete p, p = NULL; // Do this at every delete
>> |
>> | (It's a shame that 'delete' doesn't do this for you automatically.)
>> I have some diffculty to see why failing to do so is a shame; could
>> you elaborate?
>
>That's just an expression. ;) But the intent is clear, such behavior on
>part of delete would likely help catching bugs. Having a null value in a
>pointer will probably explode the program immediately and consistently on
>attempt to use it, but doing so with a value pointing to a recently deleted
>object tends to work through the test period, and end up in release code.
My experience is that although this may be so for some simple programs,
that the general end result is usually a false sense of security
especially given the attitude of many programmers. It means
conventions MUST be adhered to, and not just when delete'ing
(no doubt Dave uses an inline function or macro to do it).
It also means it is done what it may not have to be.
Furthermore, it also means in some cases that doing it (in general,
not necessarily with delete) can introduce a bug, which definitely
conflicts with helping to catch bugs :)!, a double jeopardy if ever
there was one.
- Greg
--
Comeau Computing / Comeau C/C++ ("so close" 4.2.44 betas starting)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.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 Robert Ladd" <scott@coyotegulch.com>
Date: 2000/09/18 Raw View
"David Dillard" <ddillard@usa.net> wrote
> However, if I were a commercial library writer, I can certainly imagine
that
> I might do it. Such folks surely get plenty of support calls because a
user
> of their library makes a programming error, but the error is detected (via
> dereferencing a NULL pointer) in the library. "It crashed in your
library!
> What's wrong with your code and when can I get a fix?"
Well, I can't argue with that; user support is a killer for commercial class
libraries. And don't believe the Java developers who claim it can't happen
to them; I've had more trouble with people who still manage to create
dangling references and other stupidities in Java, despite that language's
hype about being "safer" than C++.
** Scott Robert Ladd
* http://www.coyotegulch.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: Ron Natalie <ron@sensor.com>
Date: 2000/09/18 Raw View
kanze@gabi-soft.de wrote:
>
>
> The problem is that customers who call member functions with null
> pointers will also call them with other invalid pointers (freed memory,
> etc.). Checking for null here really won't avoid the calls from angry
> but culpable customers.
>
Nope, but we do the best we can. We put much more error checking into routines
that we don't control the callers of.
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/18 Raw View
"James Kuyper" <kuyper@wizard.net> wrote
> > The more interesting thing is that even if finds a null pointer
sometime, is
> > that throw really good for anything? Whoever calls a method with
no-object
> > is expected to catch exceptions and properly recover? IMHO the access
>
> If you derive your exception from std::exception, you've a decent chance
> that in critical code an outer block might catch(std::exception e) and
> examine e.what(). Whether what() will contain useful debugging
> information is up to the thrower of the exception, but it could.
Catching the exception is the easy part. (But even that is likely omitted,
if you don't expect real-life exceptions.) To make them worth anything, you
have to write the code in a proper way. Very likely the whole program. That
is not at all easy. IMHO much harder than avoiding calls to objects via a
null pointer.
And if you leave the program in an inconsistent state, it only depends on
luck, whether you got it better with the half-recovery as opposed to an
immediate termination. Imagine you're in an editor, and have an hour of work
unsaved. In case of coredump you lose that hour immediately. With the other
case you'll see some bex talking internal something error. You save, exit,
restart. Then your saved document may or may not be ill-strucured. I've seen
alike cases when a few days later the document started to crash the editor.
In that case you lose all further work. Maybe even the past work too, if you
have cyclic backups, and all the healthy documents were overwritten.
Recovering from expected exceptional situations is hard. Recovering from
bugs in your program is likely impossible.
So I'd prefer assert, ASSERTVALID and similar things to the persistent
checks. The format group does a great help catching problems in the testing
period, but to the release you have to lay out a program that is correct.
Paul
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/18 Raw View
"Balog Pal" <pasa@lib.hu> writes:
| "Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
|
| > | delete p, p = NULL; // Do this at every delete
| > |
| > | (It's a shame that 'delete' doesn't do this for you automatically.)
|
| I quite agree.
|
| > For that to happen, `delete' should require a modifiable lvalue.
|
| delete is a keyword, and the compiler could behave in an intuitive way. Like
| setting the pointer to 0 if able, and giving a warning, but continue
| otherwise. Or anything else, specified.
The fact that delete is a keyword is actually irrelevant here.
Furtermore I won't certainly want to get noise from the compiler each
time I don't use a modifiable lvalue in a delete-expression.
| I guess that is another one of the 'whoever wants that help yourselves'
| rejects, forcing the use of macros.
Again, the use of macros is not necessary --- templates should be
sufficient. And yes, the person who wants to give nifty behaviour to
his/her delete-expressions knows how to do it.
One the other hand, in modern C++ people should not be using plain
pointers throughout their programs.
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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@genuity.net>
Date: 2000/09/18 Raw View
In article <86og1ozcpb.fsf@gabi-soft.de>, <kanze@gabi-soft.de> wrote:
>The problem is that customers who call member functions with null
>pointers will also call them with other invalid pointers (freed memory,
>etc.). Checking for null here really won't avoid the calls from angry
>but culpable customers.
It will catch some, perhaps many, of them. That's better than nothing.
Why is it that people think that solutions should not be attempted unless
they're perfect?
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: Anders Pytte <anders@milkweed.com>
Date: 2000/09/14 Raw View
in article 3v9w5.13$ge7.1156@burlma1-snr2, Barry Margolin at
barmar@genuity.net wrote on 9/14/00 3:23 PM:
> In article <A%6w5.54564$58.6565272@typhoon.tampabay.rr.com>,
> Scott Robert Ladd <scottrobertladd@hotmail.com> wrote:
>> Now, perhaps I'm dense (no comments), but it seems illogical that I can call
>> a method through a NULL pointer. I well-understand *why* this is possible;
>> it even makes sense from a compiler perspective, since the call
>> c_obj->M1(*int_obj) is really implemented as M1(&c_obj,*int_obj).
>
> In fact, this is the major difference between regular member functions and
> virtual member functions. Non-virtual members can be resolved by static
> type analysis, so it's not necessary to dereference the pointer.
So can virtual member functions, when the static type is known by the
compiler to be the same as the virtual type, which can be often:
class B { public: virtual void foo(); }
B b;
b.foo();
Why would the compiler bother with a vtable lookup in the above situation?
The usage described by the OP assumes that the pointer value on which the
function is called has been set to NULL:
class B { public: virtual void foo(); }
B* b = NULL;
b->foo(); // throw here rather than operate on NULL
I'd bet the throw statement was placed there not as a general policy but
because a specific engineering error was suspected, but there was no time to
track it down.
Anders.
--
Anders Pytte Milkweed Software
PO Box 32 voice: (802) 586-2545
Craftsbury, VT 05826 email: anders@milkweed.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 Dillard" <ddillard@usa.net>
Date: 2000/09/14 Raw View
"Scott Robert Ladd" <scottrobertladd@hotmail.com> wrote in message
news:A%6w5.54564$58.6565272@typhoon.tampabay.rr.com...
> My bottom line: You can break *any* part of C++ by using poor coding
> practices, and it is impractical (and likely impossible) to build in
checks
> for every possible happenstance and idiocity.
>
> Opinions? Thoughts? Over-ripe fruit? ;)
Personally, I think checking for a NULL this pointer is somewhat
overzealous. It will work for non-virtual methods, but not for virtual
methods.
However, if I were a commercial library writer, I can certainly imagine that
I might do it. Such folks surely get plenty of support calls because a user
of their library makes a programming error, but the error is detected (via
dereferencing a NULL pointer) in the library. "It crashed in your library!
What's wrong with your code and when can I get a fix?"
--- David
---
[ 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 Robert Ladd" <sladd@tampabay.rr.com>
Date: 2000/09/14 Raw View
Barry Margolin <barmar@genuity.net> wrote:
> And the reason it's not caught is due to the philosophy inherited from C:
> the code generated should be the minimum necessary to implement the
> language, there shouldn't be extraneous runtime checks.
True; I'd just never thought it through before. And the "if (this == NULL)"
check violates the above principle; it checks for NULL for *every* call to
the method, even those that come from actual objects and references. So if
my program never calls that function through a pointer, the check is simply
wasting CPU time...
> You can probably find "checkout" compilers that are designed for debugging
that
> will put in checks for null pointers, array bounds, etc., but most
compilers don't.
Thank the gods they don't! ;) In most cases, such checks would be useless
overhead -- exactly like doing "if (this == NULL) throw X".
> "this" isn't a reference, it's a pointer, isn't it?
Ah -- a secondary issue I should have put in a separate message. The same
person who is paranoid of NULL "this" is also fond of checking LOTS of
references to see if they point to NULL. Again, this seems to be
poorly-placed paranoia...
I always check pointers for "NULLness" -- when I allocate a pointer with
new, or receive a pointer as an argument, or when the pointer is volatile.
THAT makes sense. But checking every call to a member function for "this ==
NULL" seems excessive AND expensive.
--
** Scott Robert Ladd
Coyote Gulch Productions - http://www.coyotegulch.com
Home of JISP - the Java Indexed Serialization Package
(A tool for creating databases without JDBC, Access or SQL)
---
[ 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 Robert Ladd" <sladd@tampabay.rr.com>
Date: 2000/09/14 Raw View
Ron Natalie <ron@sensor.com> wrote:
> Yep, you've learned rule #1 about undefined behavior, the program may
continue
> normally and get ill a significant distance from the point of infraction.
I'm acquainted with undefined behavior; almost any language (programming or
otherwise) is liable to invalid or illogical use. The code in question,
however, seems as paranoid as a an X-Files fan...
The real question is: How much is too much caution? And is the caution
properly placed? Note that the author of the code puts this test at the
beginning of DOZENS of methods, not just one... A C++ philosophy is
"Features only have a cost if they're used." Every invocation of the
method -- including those through objects and object references -- will
incur the overhead for verification.
It had never occured to me that someone would invoke a member function via a
NULL pointer -- and I have yet to see any code, in any book or library, test
"this" for NULL. I'm willing to bet the author of the code was bitten badly
once, and they've decided to err on the side of caution.
Do *you* have an "if (this == NULL)" at the beginning of all your methods?
The check is, to my eye, misplaced. Looking for NULL should occur when the
object is first allocated, or when the pointer is passed in from some
outside source.
Programming is often a matter of risk management; you need a weigh the
possibility of a "disaster" against the expense of preventing it.
--
** Scott Robert Ladd
Coyote Gulch Productions - http://www.coyotegulch.com
Home of JISP - the Java Indexed Serialization Package
(A tool for creating databases without JDBC, Access or SQL)
---
[ 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 <david@tribble.com>
Date: 2000/09/15 Raw View
Barry Margolin <barmar@genuity.net> wrote:
>> [...]
>> "this" isn't a reference, it's a pointer, isn't it?
Scott Robert Ladd wrote:
> Ah -- a secondary issue I should have put in a separate message. The
> same person who is paranoid of NULL "this" is also fond of checking
> LOTS of references to see if they point to NULL. Again, this seems to
> be poorly-placed paranoia...
Except when it's possible, in client code you can't control, that
a client passes you a null reference. It's undefined behavior, but
most compilers won't catch it at runtime.
> I always check pointers for "NULLness" -- when I allocate a pointer
> with new, or receive a pointer as an argument, or when the pointer is
> volatile. THAT makes sense. But checking every call to a member
> function for "this == NULL" seems excessive AND expensive.
Unfortunately, checking for null only solves part of the problem.
You can't check that a pointer points to a deleted/unallocated
object, or can't check (in general) that a pointer contains an
invalid (unmapped virtual) address. Passing around dangling pointers
to long-since deleted objects is probably more common than passing
null pointers around.
Some defensive programming can help in these cases (at least in your
code):
delete p, p = NULL; // Do this at every delete
(It's a shame that 'delete' doesn't do this for you automatically.)
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/15 Raw View
"Scott Robert Ladd" <scottrobertladd@hotmail.com> wrote:
>> My bottom line: You can break *any* part of C++ by using poor coding
>> practices, and it is impractical (and likely impossible) to build in
>> checks for every possible happenstance and idiocity.
David Dillard wrote:
> Personally, I think checking for a NULL this pointer is somewhat
> overzealous. It will work for non-virtual methods, but not for
> virtual methods.
>
> However, if I were a commercial library writer, I can certainly
> imagine that I might do it. Such folks surely get plenty of support
> calls because a user of their library makes a programming error, but
> the error is detected (via dereferencing a NULL pointer) in the
> library. "It crashed in your library! What's wrong with your code
> and when can I get a fix?"
Indeed. Most defensive programming tactics assume that you don't
have any control over the clients of your class (library), so you
go out of your way to add preconditions and postconditions to catch
damaging circumstances early. (This is part of "programming by
contract" popularized by Bertrand Meyer.)
On the other hand, if you're the only user of one of your classes
and always will be, then such checks could be considered extraneous.
But beware the day when you decide to publicize your heretofore
private class to the rest of the world. At that point, you'd
probably wished its functions were a little more robust in checking
for client indiscretions.
As for the particular case of 'this' being null, consider cases
where you've got a pointer to an object stashed away somewhere in
your class, which you then set to null, and then you later use it
to invoke one of its member functions but forget to check the pointer
for null. For example:
class Foo
{
public:
void update(); // Do something to *this
...
};
class Client
{
private:
Foo * m_foo; // A pointer
...
public:
void prepare(Foo *o)
{
m_foo = o; // [A]
}
void process()
{
// Forgot to check that m_foo != NULL
m_foo->update(); // [B]
...
}
void release()
{
m_foo = NULL; // [C]
}
};
void otherClient(Client *cl, Foo *f)
{
cl->prepare(f);
...
cl->release();
...
cl->process(); // Oops! Fails at [B]
...
}
Even more insidious errors can occur with null (unbound) references,
e.g.:
class Bar
{
private:
Foo & m_foo; // A reference
...
public:
Bar(Foo &o): m_foo(o) // [D]
{ ... }
void process()
{
// Did not check that &m_foo != NULL
m_foo.update(); // [E]
...
}
};
void proc(Foo *f)
{
Bar * b;
// Forgot to check that f != NULL
b = new Bar(*f); // [F]
...
b->process(); // Fails at [E] if f was null
...
}
It's undefined behavior to dereference a null pointer, but due to
the way most compilers implement references, the bug at [F] will
probably not cause a runtime error, leaving the error undetected
until [E] is reached.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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 <david@tribble.com>
Date: 2000/09/15 Raw View
Scott Robert Ladd wrote:
> Programming is often a matter of risk management; you need a weigh the
> possibility of a "disaster" against the expense of preventing it.
Part of the consideration is the answer to the question, "How much
damage will result if such an error is not detected early enough?"
The answer indicates a different amount of willingness to go through
the effort of adding extra error checks; consider, for example,
the answers given for a video game program versus a nuclear power
plant monitoring program.
Tribble's Levels of Software Trust
Do you trust the software enough to...
1. run a video game?
2. print your payroll check?
3. operate a heart-lung machine?
4. operate a nuclear power plant?
Most of my code must operate at level 2. When such code fails, it
usually means some down time for customers, who then either restart
the program,or at worst, reboot the computer. Failures at higher
levels are not so easily forgiven.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/15 Raw View
"Scott Robert Ladd" <sladd@tampabay.rr.com> wrote
> True; I'd just never thought it through before. And the "if (this ==
NULL)"
> check violates the above principle; it checks for NULL for *every* call to
> the method, even those that come from actual objects and references.
The more interesting thing is that even if finds a null pointer sometime, is
that throw really good for anything? Whoever calls a method with no-object
is expected to catch exceptions and properly recover? IMHO the access
violation resulting from the 0 pointer is likely as good as the unhandled or
mis-handled exception.
> > "this" isn't a reference, it's a pointer, isn't it?
>
> Ah -- a secondary issue I should have put in a separate message. The same
> person who is paranoid of NULL "this" is also fond of checking LOTS of
> references to see if they point to NULL. Again, this seems to be
> poorly-placed paranoia...
I agree. However there are ways to have a ref set up to 0 or some ill value,
anyone should expect it points to a valid object. If not, it's the caller's
problem.
> I always check pointers for "NULLness" -- when I allocate a pointer with
> new, or receive a pointer as an argument,
I have other policy. For new I never check. new should never return null.
However I certainly check at malloc, or other allocations.
For params I only check if NULL has a meaning (like 'ignore' or 'use
default'), or when param checking is specified for the function, and a param
error-reporting protocoll estabilished. (That is likely not an exception, or
a specific exception). For other cases params go unchecked, and the caller
promises the good values. If a trash pointer gets passed, it's pretty low
chance to be exactly NULL, and all the other cases you can't reliably tell
it has a bad value anyway.
>or when the pointer is volatile.
And this one is really interesting. What good result you expect from that?
At the time you check it is not null, and in the next, when you dereference
it, it can be NULL. So checking it seems unwise. Create a nonvolatile copy
and check that, and use that later on.
> THAT makes sense.
Paul
---
[ 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 Robert Ladd" <sladd@tampabay.rr.com>
Date: 2000/09/15 Raw View
> Why would the compiler bother with a vtable lookup in the above situation?
Some compilers *will* make a direct call to a virtual method, skipping the
vtable lookup if the precise type of the target object is known.
--
** Scott Robert Ladd
Coyote Gulch Productions - http://www.coyotegulch.com
&^%#$!! Please ignore the previous sigs with ads for Jisp!
---
[ 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: Gabriel Dos Reis <gdr@codesourcery.com>
Date: 2000/09/15 Raw View
David R Tribble <david@tribble.com> writes:
[...]
| Some defensive programming can help in these cases (at least in your
| code):
|
| delete p, p = NULL; // Do this at every delete
|
| (It's a shame that 'delete' doesn't do this for you automatically.)
For that to happen, `delete' should require a modifiable lvalue. And
I have some diffculty to see why failing to do so is a shame; could
you elaborate?
--
Gabriel Dos Reis, gdr@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
http://www.codesourcery.com/gcc-compile.shtml
---
[ 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: Anders Pytte <anders@milkweed.com>
Date: 2000/09/15 Raw View
in article 39C24FAC.10BBE606@tribble.com, David R Tribble at
david@tribble.com wrote on 9/15/00 12:48 PM:
> Barry Margolin <barmar@genuity.net> wrote:
>>> [...]
>>> "this" isn't a reference, it's a pointer, isn't it?
>
> Scott Robert Ladd wrote:
>> Ah -- a secondary issue I should have put in a separate message. The
>> same person who is paranoid of NULL "this" is also fond of checking
>> LOTS of references to see if they point to NULL. Again, this seems to
>> be poorly-placed paranoia...
>
> Except when it's possible, in client code you can't control, that
> a client passes you a null reference. It's undefined behavior, but
> most compilers won't catch it at runtime.
>
>> I always check pointers for "NULLness" -- when I allocate a pointer
>> with new, or receive a pointer as an argument, or when the pointer is
>> volatile. THAT makes sense. But checking every call to a member
>> function for "this == NULL" seems excessive AND expensive.
>
> Unfortunately, checking for null only solves part of the problem.
> You can't check that a pointer points to a deleted/unallocated
> object, or can't check (in general) that a pointer contains an
> invalid (unmapped virtual) address. Passing around dangling pointers
> to long-since deleted objects is probably more common than passing
> null pointers around.
>
> Some defensive programming can help in these cases (at least in your
> code):
>
> delete p, p = NULL; // Do this at every delete
>
> (It's a shame that 'delete' doesn't do this for you automatically.)
I agree; however, then you could not delete const pointers:
int main()
{
char* const data = new char[16];
delete data; data = 0; // rejected
}
Anders.
--
Anders Pytte Milkweed Software
PO Box 32 voice: (802) 586-2545
Craftsbury, VT 05826 email: anders@milkweed.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: Stephen Clamage <stephen.clamage@sun.com>
Date: 2000/09/15 Raw View
On Thu, 14 Sep 2000 23:57:17 GMT, "Scott Robert Ladd"
<sladd@tampabay.rr.com> wrote:
>The real question is: How much is too much caution? And is the caution
>properly placed? Note that the author of the code puts this test at the
>beginning of DOZENS of methods, not just one...
>
>It had never occured to me that someone would invoke a member function via a
>NULL pointer -- ...
>
Checking for this==0 inside a member function will catch a null "this"
pointer when the function doesn't need to be invoked via the vtable,
AND when no pointer conversion (e.g. derived to one of multiple bases)
is needed. Otherwise, the function won't be entered at all, or the
pointer will likely have some non-null nonsense value.
>The check is, to my eye, misplaced. Looking for NULL should occur when the
>object is first allocated, or when the pointer is passed in from some
>outside source.
I agree completely.
---
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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/09/15 Raw View
"Scott Robert Ladd" <sladd@tampabay.rr.com> writes:
>Barry Margolin <barmar@genuity.net> wrote:
>> And the reason it's not caught is due to the philosophy inherited from C:
>> the code generated should be the minimum necessary to implement the
>> language, there shouldn't be extraneous runtime checks.
>
>True; I'd just never thought it through before. And the "if (this == NULL)"
>check violates the above principle; it checks for NULL for *every* call to
>the method, even those that come from actual objects and references. So if
>my program never calls that function through a pointer, the check is simply
>wasting CPU time...
Not necessarily. An optimizing C++ implementation is quite free to
optimize such checks away! (Not that I happen to know of any that do...)
A good debugging C++ implementation should provide a way to perform
such checks automatically. So if you have a good debugging C++
implementation, they're not needed. (Not that I know of any such
implementations...)
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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@genuity.net>
Date: 2000/09/15 Raw View
In article <Mmdw5.45283$98.4183813@typhoon.tampabay.rr.com>,
Scott Robert Ladd <sladd@tampabay.rr.com> wrote:
>Barry Margolin <barmar@genuity.net> wrote:
>> And the reason it's not caught is due to the philosophy inherited from C:
>> the code generated should be the minimum necessary to implement the
>> language, there shouldn't be extraneous runtime checks.
>
>True; I'd just never thought it through before. And the "if (this == NULL)"
>check violates the above principle; it checks for NULL for *every* call to
>the method, even those that come from actual objects and references. So if
>my program never calls that function through a pointer, the check is simply
>wasting CPU time...
The philosophy refers to the C *implementation*. The idea is that there
shouldn't be anything happening that the programmer doesn't know about.
Programmers who want their programs to be robust can add the checks,
programmers who care more about performance than safety can leave them out.
>I always check pointers for "NULLness" -- when I allocate a pointer with
>new, or receive a pointer as an argument, or when the pointer is volatile.
>THAT makes sense. But checking every call to a member function for "this ==
>NULL" seems excessive AND expensive.
In the programming shop I referred to earlier, I think our policy was that
such checks should be performed by high-level public interfaces. But we
generally didn't put them in the low-level routines that tended to be
called in inner loops. The overhead of a pointer check in a function that
takes a page or more of code is negligible, so it's worth it to catch stray
pointers.
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: "Marco Manfredini" <marco@no-spam-to-taris.de>
Date: 2000/09/15 Raw View
Checking for this!=NULL is a weak excuse a programmer can give for C++'s
very relaxed NULL handling.
Not only, that it doesn't work in a virtual member function. That check also
fails, if the NULL Pointer gets implicitly converted in a base member call:
class A
{
int ma;
void a() { assert(this!=NULL); ma=3; }
};
class B
{
int mb;
void mb() { assert(this!=NULL); mb=4; }
};
class C : public A, public B {};
int main()
{
C *c=NULL;
c->mb(); // here, the c pointer gets "adjusted" to point to the B part of
C.
// the actual value depends on your implementation, but you can
expect
// 'this' in B::mb() to be different from NULL (for example NULL+4).
}
Checking in the member function is usually too late.
It -is- possible to wrap the usage of pointers inside smart-pointer template
which check NULL dereferences (and thus make it impossible to create an
invalide reference too) and handle conversions in such a way, that they
don't change NULL pointers.
But I feel, that NULL-correctness is more a matter of a compiler switch: the
Standard describes a lot of situations, where an operation can have an
undefined behaviour (and mistreating a NULL pointers is just one of them).
Even if runtime-checking for undefined behaviour might be quite expensive, I
don't see why my compiler can't have a switch which generates code to check
that and to throw an exception (which should be defined in the Standard) to
signal that my program has been gone into an undefined state.
A "strict" evaluation mode would'n violate the "You pay for what you need"
philosophy, since I am paying only when I turn the switch on...
--
Marco
---
[ 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: Ron Natalie <ron@sensor.com>
Date: 2000/09/15 Raw View
Scott Robert Ladd wrote:
>
> The real question is: How much is too much caution? And is the caution
> properly placed? Note that the author of the code puts this test at the
> beginning of DOZENS of methods, not just one... A C++ philosophy is
> "Features only have a cost if they're used." Every invocation of the
> method -- including those through objects and object references -- will
> incur the overhead for verification.
Depends on the severity of the infraction and how likely it is to be abused.
If I was writing a library that was to be used by lame programmer-wannabees
in the field, I am VERY careful. Staves off a lot of problems, you wont believe
the rediculous ways people come up with to call library functions (Casting
should required the root password I believe at times).
> Do *you* have an "if (this == NULL)" at the beginning of all your methods?
No, I have "assert(this)" on methods that are intended to be called from outside
of our development group.
>
> The check is, to my eye, misplaced. Looking for NULL should occur when the
> object is first allocated, or when the pointer is passed in from some
> outside source.
That is what I was saying. While I'll generally break the fingers of anybody
who intentionally abuses NULL pointers in our development group, and we test
our own code (additionaly with the help of things like purify), I'm very leary
about allowing other programmers outside of our company into the same executable
with our code (I really like to separate them with some piece of IPC that I also
carefully error check).
Yes, if one of my guys started every method function with "assert(this)" I would
have a talk with him (we did have someone who liked using this-> )
---
[ 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 <david@tribble.com>
Date: 2000/09/15 Raw View
Scott Robert Ladd wrote:
> The real question is: How much is too much caution? And is the caution
> properly placed? Note that the author of the code puts this test at
> the beginning of DOZENS of methods, not just one... A C++ philosophy
> is "Features only have a cost if they're used." Every invocation of
> the method -- including those through objects and object references --
> will incur the overhead for verification.
Although the overhead of checking for a null pointer is extremely
small. Especially compared to any I/O done by your code.
> Do *you* have an "if (this == NULL)" at the beginning of all your
> methods?
> The check is, to my eye, misplaced. Looking for NULL should occur when
> the object is first allocated, or when the pointer is passed in from
> some outside source.
This is a generally true.
--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.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: Barry Margolin <barmar@genuity.net>
Date: 2000/09/15 Raw View
In article <39C24FAC.10BBE606@tribble.com>,
David R Tribble <david@tribble.com> wrote:
>Unfortunately, checking for null only solves part of the problem.
>You can't check that a pointer points to a deleted/unallocated
>object, or can't check (in general) that a pointer contains an
>invalid (unmapped virtual) address. Passing around dangling pointers
>to long-since deleted objects is probably more common than passing
>null pointers around.
That's life -- you check what you can, and have to live with not being able
to catch everything. It's not perfect, but it's better than nothing.
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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: "Balog Pal" <pasa@lib.hu>
Date: 2000/09/15 Raw View
"Gabriel Dos Reis" <gdr@codesourcery.com> wrote in message
> | delete p, p = NULL; // Do this at every delete
> |
> | (It's a shame that 'delete' doesn't do this for you automatically.)
I quite agree.
> For that to happen, `delete' should require a modifiable lvalue.
delete is a keyword, and the compiler could behave in an intuitive way. Like
setting the pointer to 0 if able, and giving a warning, but continue
otherwise. Or anything else, specified.
I guess that is another one of the 'whoever wants that help yourselves'
rejects, forcing the use of macros.
> And
> I have some diffculty to see why failing to do so is a shame; could
> you elaborate?
That's just an expression. ;) But the intent is clear, such behavior on
part of delete would likely help catching bugs. Having a null value in a
pointer will probably explode the program immediately and consistently on
attempt to use it, but doing so with a value pointing to a recently deleted
object tends to work through the test period, and end up in release code.
Paul
---
[ 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: 2000/09/15 Raw View
Balog Pal wrote:
...
> The more interesting thing is that even if finds a null pointer sometime, is
> that throw really good for anything? Whoever calls a method with no-object
> is expected to catch exceptions and properly recover? IMHO the access
If you derive your exception from std::exception, you've a decent chance
that in critical code an outer block might catch(std::exception e) and
examine e.what(). Whether what() will contain useful debugging
information is up to the thrower of the exception, but it could.
---
[ 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 Robert Ladd" <scottrobertladd@hotmail.com>
Date: 2000/09/14 Raw View
I recently encounterd a commercial class library that includes what appeared
to be odd and useless code:
void C::M(const int & ref)
{
if (!this)
throw ...;
if (&ref == 0)
throw ...;
}
I quite pompously informed the author of the above code that he was wasting
CPU cycles, since:
A) if you've reach the method, "this" cannot be NULL, and
B) a reference must be instantiated with a valid object, so it can't be
NULL.
The author disagreed. Rather than dismiss him out-of-hand, I wrote a test
program -- and was promptly hoisted by my own petard. Here is my complete
test program:
#include <iostream>
#include <iomanip>
using namespace std;
class C
{
public:
int V;
void M1(const int & ref)
{
if (!this)
cout << "this == NULL" << endl;
if (&ref == 0)
cout << "&ref == 0" << endl;
// if this == NULL, this line cases an error
// V = 0;
}
virtual void M2(const int & ref)
{
// nada
}
};
int main()
{
C * c_obj = NULL;
int * int_obj = NULL;
// This line crashes with a "Null Reference" exception"
// c_obj->V = 0;
// this line crashes with a "Null Reference" exception"
// c_obj->M2(*int_obj);
// BUT THIS LINE RUNS!
c_obj->M1(*int_obj);
// Visual C++ 6.0 SP3 on i86 generates this machine
// code for the line above:
// mov eax,dword ptr [ebp-8]
// push eax
// mov ecx,dword ptr [ebp-4]
// call @ILT+105(C::M1)
return 0;
}
Indeed, I cannot access members V or M2 through a NULL object pointer -- but
*I CAN* call M1 through the NULL pointer, because MSVC++ treats the "this"
pointer as an argument, thus never dereferencing it and avoiding any NULL
pointer problems.
A secondary (and in my mind, minor) issue is the ability to assign a
reference to a non-object by dereferencing a NULL pointer. The literature is
very explicit about how "there is no such thing as a NULL reference" --
well, there *is* a possibility of null references, even if it does involve a
pointer contortion.
Now, perhaps I'm dense (no comments), but it seems illogical that I can call
a method through a NULL pointer. I well-understand *why* this is possible;
it even makes sense from a compiler perspective, since the call
c_obj->M1(*int_obj) is really implemented as M1(&c_obj,*int_obj).
I'm an old-enough C/C++ hand to know that you can circumvent any security
features in the language with injudicious casts and crazy constructs. *I*
think this is all a tempest in a tea kettle, since NULL pointers will
express themselves in many ways that don't require gratuitous checks;
however, the author of the library insists that "fail safe" code needs to
check "this" pointers and references for NULL.
I've *never* checked "this" for NULL, in any application, nor have I ever
expected a "NULL" reference. I don't have any of the "standard" literature
at hand, but I don't remember Bjarne or Koenig ever checking to see if
"this" was NULL...
My bottom line: You can break *any* part of C++ by using poor coding
practices, and it is impractical (and likely impossible) to build in checks
for every possible happenstance and idiocity.
Opinions? Thoughts? Over-ripe fruit? ;)
** Scott Robert Ladd
* http://www.coyotegulch.com
* http://www.maximal.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: Ron Natalie <ron@sensor.com>
Date: 2000/09/14 Raw View
Scott Robert Ladd wrote:
>
> I recently encounterd a commercial class library that includes what appeared
> to be odd and useless code:
>
> void C::M(const int & ref)
> {
> if (!this)
> throw ...;
Yep, you've learned rule #1 about undefined behavior, the program may continue
normally and get ill a significant distance from the point of infraction. A
benefit of these checks is that it brings about the failure quicker. Generally,
I'd put these in using assert macros. I'm sure the library provider found it
easier to puke in a defined way than to have the code coredump with a stack
trace pointing into his library (and angry, even if culpable, customers griping
about bugs in his code).
---
[ 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@genuity.net>
Date: 2000/09/14 Raw View
In article <A%6w5.54564$58.6565272@typhoon.tampabay.rr.com>,
Scott Robert Ladd <scottrobertladd@hotmail.com> wrote:
>Now, perhaps I'm dense (no comments), but it seems illogical that I can call
>a method through a NULL pointer. I well-understand *why* this is possible;
>it even makes sense from a compiler perspective, since the call
>c_obj->M1(*int_obj) is really implemented as M1(&c_obj,*int_obj).
In fact, this is the major difference between regular member functions and
virtual member functions. Non-virtual members can be resolved by static
type analysis, so it's not necessary to dereference the pointer.
And the reason it's not caught is due to the philosophy inherited from C:
the code generated should be the minimum necessary to implement the
language, there shouldn't be extraneous runtime checks. You can probably
find "checkout" compilers that are designed for debugging that will put in
checks for null pointers, array bounds, etc., but most compilers don't.
>A secondary (and in my mind, minor) issue is the ability to assign a
>reference to a non-object by dereferencing a NULL pointer. The literature is
>very explicit about how "there is no such thing as a NULL reference" --
>well, there *is* a possibility of null references, even if it does involve a
>pointer contortion.
"this" isn't a reference, it's a pointer, isn't it?
>My bottom line: You can break *any* part of C++ by using poor coding
>practices, and it is impractical (and likely impossible) to build in checks
>for every possible happenstance and idiocity.
This is true, but there are many obvious errors that you can be prepared
for. And if the overhead of checking them isn't too great, you might as
well. When I was a programmer, our organization's policy was that we not
only checked pointers for nullness, but all our structures had a header
containing a sentinel with an abbreviated name for the structure and
version of the structure, and we checked that as well (with dynamic linking
it was possible that a new version of a library would be called with an old
version of the parameter structure, and it used the version part of the
sentinel to provide backward compatibility).
--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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 ]