Topic: How many bytes will delete Delete?


Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/11/29
Raw View
In article <3A240B97.E5349CC1@ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>No, you're still assuming that all alignments are multiples of each
>other. Say we had a strange machine where ints were on 3-byte boundaries
>and floats on 4-byte (ignore other types for now). Now we allocate
>char[6], expecting to be able to store two ints in it. "The most
>stringent alignment requirement of any object type whose size is no
>greater than the size of the array being created" is 4 bytes, so the
>array only needs to be aligned on a multiple of 4, and may not be
>properly aligned for an int.

This is one of those academic arguments. Now focus on the real World. I
will consider this problem if either you can demonstrate a machine where
it is a problem or a reason why someone might design such a machine.

However your argument still fails, because the array of char must be
placed on a 12 byte boundary, now it will hold either two ints or a
float with a couple of bytes to spare.


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: "Steve Burt" <steve.burt@cursor-system.com>
Date: 2000/11/29
Raw View
Ross Smith <ross.s@ihug.co.nz> wrote in message
news:3A24352A.E649AE46@ihug.co.nz...
> wmm@fastdial.net wrote:
> >
> No. I've heard of one piece of big iron (I forget which -- one of the
> early Crays?) that had 48-bit ints and 64-bit floats, but that was
> because ints were stored in the mantissa part of an FP register, so I
> expect all storage was 64-bit-aligned anyway. I've also heard of an old
> video game CPU that had integers and pointers of mismatched sizes (I
> forget the exact figures but it was something like 10 vs 14 bits), but I
> doubt very much that it's still in use, or that it ever had a C (never
> mind C++) compiler when it was.
>

A blast from the past! The Mattel Intellivision used a General Instruments
processor called the 1610.
This had 16 bit registers, but 10 bit instruction words (generally referred
to as decles). Since we only ever used Assembly language to program the
thing, alignment was not an issue.... (but the spare bits when loading
registers from ROM could occasionally be used for devious things).


---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ross Smith <ross.s@ihug.co.nz>
Date: 2000/11/29
Raw View
Francis Glassborow wrote:
>
> In article <3A240B97.E5349CC1@ihug.co.nz>, Ross Smith
> <ross.s@ihug.co.nz> writes
> >No, you're still assuming that all alignments are multiples of each
> >other. Say we had a strange machine where ints were on 3-byte boundaries
> >and floats on 4-byte (ignore other types for now). Now we allocate
> >char[6], expecting to be able to store two ints in it. "The most
> >stringent alignment requirement of any object type whose size is no
> >greater than the size of the array being created" is 4 bytes, so the
> >array only needs to be aligned on a multiple of 4, and may not be
> >properly aligned for an int.
>
> This is one of those academic arguments. Now focus on the real World. I
> will consider this problem if either you can demonstrate a machine where
> it is a problem or a reason why someone might design such a machine.

Oh, I quite agree. I don't consider it a problem either. But this is
comp.std.c++, not comp.realworld.c++. :-)

> However your argument still fails, because the array of char must be
> placed on a 12 byte boundary, now it will hold either two ints or a
> float with a couple of bytes to spare.

How do you arrive at that? The standard only requires a multiple of the
_most stringent_ alignment, not of _all_ of them. (I'll grant you the
_intention_ was probably to require all of them, but that's not what it
actually says.)

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"But for a pop culture junkie, cyberspace is the final frontier. Where
else can you find more pop, culture, and junk?" -- Diana Wichtel

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ron Natalie <ron@sensor.com>
Date: 2000/11/29
Raw View

Ross Smith wrote:

>
> How do you arrive at that? The standard only requires a multiple of the
> _most stringent_ alignment, not of _all_ of them. (I'll grant you the
> _intention_ was probably to require all of them, but that's not what it
> actually says.)
>
Now you've lost me.  If it is conforms to the MOST STRINGENT alignment
how can it not conform to the others?

---
[ comp.std.c++ is moderated.  To submit articles, try 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.Kanze@dresdner-bank.com
Date: 2000/11/30
Raw View
In article <3A256C74.509F15B3@sensor.com>,
  Ron Natalie <ron@sensor.com> wrote:

> Ross Smith wrote:

> > How do you arrive at that? The standard only requires a multiple
> > of the _most stringent_ alignment, not of _all_ of them. (I'll
> > grant you the _intention_ was probably to require all of them, but
> > that's not what it actually says.)

> Now you've lost me.  If it is conforms to the MOST STRINGENT
> alignment how can it not conform to the others?

I thought he'd already posted an example.  Anyway, suppose that double
requires an alignment of 8, and int an alignment of 6.  The most
stringent alignment is 8, but not all addresses aligned for 8 will
also be aligned for 6.

And as he says, it's not a real problem, because 1) the case doesn't
occur in real life, and 2) even if it did, market forces would ensure
that in fact, the compiler ensured an alignment for all types, and not
just the most stringent.  It's probably worth fixing the wording in
the standard, when the occasion presents itself, but it certainly
isn't something that has to be handled with high priority, or that is
worth a lot of effort.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


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: James Kuyper <kuyper@wizard.net>
Date: 2000/11/30
Raw View
Ron Natalie wrote:
>
> Ross Smith wrote:
>
> >
> > How do you arrive at that? The standard only requires a multiple of the
> > _most stringent_ alignment, not of _all_ of them. (I'll grant you the
> > _intention_ was probably to require all of them, but that's not what it
> > actually says.)
> >
> Now you've lost me.  If it is conforms to the MOST STRINGENT alignment
> how can it not conform to the others?

If the MOST STRINGENT alignment is not the least common multiple of ALL
of the other alignments. In the example given the relevant alignements
were 3 and 4. The most stringent alignement was 4. Therefore, a request
for 6 bytes must be aligned on a multiple of 4, but needn't be aligned
on a multiple of 3. That was almost certainly not the intent of the
author.

---
[ comp.std.c++ is moderated.  To submit articles, try 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/11/28
Raw View
Ross Smith wrote:

> Don't use leading underscores. Many names beginning with an underscore
> are reserved for the implementation; the exact rules for which names are
> reserved under various circumstances are complicated, and the usual
> advice is not to bother memorising them and just avoid leading
> underscores everywhere.

Good advice.

Now what about the combination of both leading and trailing underscores
exemplified by:

struct S {
    int data;
    // more ...
    char _[ pad_len ];    // <--
};


---
[ comp.std.c++ is moderated.  To submit articles, try 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: wmm@fastdial.net
Date: 2000/11/28
Raw View
In article <3A22D0CB.2478A6E5@ihug.co.nz>,
  Ross Smith <ross.s@ihug.co.nz> wrote:
> wmm@fastdial.net wrote:
> >
> > 5.3.4p10:
> >
> >     For arrays of char and unsigned char, the difference between
> >     the result of the new-expression and the address returned by
> >     the allocation function shall be an integral multiple of the
> >     most stringent alignment requirement (3.9) of any object
> >     type whose size is no greater than the size of the array
> >     being created. [Note: Because allocation functions are
> >     assumed to return pointers to storage that is appropriately
> >     aligned for objects of any type, this constraint on array
> >     allocation overhead permits the common idiom of allocating
> >     character arrays into which objects of other types will later
> >     be placed. ]
>
> I take your point and agree I was wrong by the stated intent of the
> standard, but a real nitpicker (who, me?) might argue that the
> requirement that "the difference ... shall be an integral multiple of
> the most stringent alignment requirement" is not enough to guarantee
> correct alignment. There is, as far as I can tell, no requirement that
> the alignment of every type be a multiple of the alignment of every
> smaller type, which would be necessary for the paragraph above to work
> as intended.

No, I think the wording is fine as written.  What it basically
says is that a buffer of size N must have sufficiently stringent
alignment to accommodate _any_ object whose size is N or less.
If, for instance, a short were required to begin on a 4-byte
boundary and a double could begin on any 2-byte boundary, the
result of "new char[sizeof(double)]" would be required to begin
(at least) on a 4-byte boundary because a short will fit into a
sizeof(double) buffer.

--
William M. Miller, wmm@fastdial.net
Vignette Corporation (www.vignette.com)


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: Ron Natalie <ron@sensor.com>
Date: 2000/11/28
Raw View

Ross Smith wrote:
>
>
> This is non-portable. Casting a pointer from one arbitrary type to
> another is not required to produce a valid result. (For example, the
> space you allocated might not be correctly aligned for an M, since you
> lied to the compiler by claiming you were only going to store chars in
> it.)

Well, in general it's not a safe thing, because not all char*'s may be
suitably aligned, however in this case, their is a goofy distinction made.
New char[...] does return a value suitable for the most stringent alignment
of any datatype (5.3.4/10).

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ross Smith <ross.s@ihug.co.nz>
Date: 2000/11/28
Raw View
wmm@fastdial.net wrote:
>
> In article <3A22D0CB.2478A6E5@ihug.co.nz>,
>   Ross Smith <ross.s@ihug.co.nz> wrote:
> > wmm@fastdial.net wrote:
> > >
> > > 5.3.4p10:
> > >
> > >     For arrays of char and unsigned char, the difference between
> > >     the result of the new-expression and the address returned by
> > >     the allocation function shall be an integral multiple of the
> > >     most stringent alignment requirement (3.9) of any object
> > >     type whose size is no greater than the size of the array
> > >     being created. [Note: Because allocation functions are
> > >     assumed to return pointers to storage that is appropriately
> > >     aligned for objects of any type, this constraint on array
> > >     allocation overhead permits the common idiom of allocating
> > >     character arrays into which objects of other types will later
> > >     be placed. ]
> >
> > I take your point and agree I was wrong by the stated intent of the
> > standard, but a real nitpicker (who, me?) might argue that the
> > requirement that "the difference ... shall be an integral multiple of
> > the most stringent alignment requirement" is not enough to guarantee
> > correct alignment. There is, as far as I can tell, no requirement that
> > the alignment of every type be a multiple of the alignment of every
> > smaller type, which would be necessary for the paragraph above to work
> > as intended.
>
> No, I think the wording is fine as written.  What it basically
> says is that a buffer of size N must have sufficiently stringent
> alignment to accommodate _any_ object whose size is N or less.
> If, for instance, a short were required to begin on a 4-byte
> boundary and a double could begin on any 2-byte boundary, the
> result of "new char[sizeof(double)]" would be required to begin
> (at least) on a 4-byte boundary because a short will fit into a
> sizeof(double) buffer.

No, you're still assuming that all alignments are multiples of each
other. Say we had a strange machine where ints were on 3-byte boundaries
and floats on 4-byte (ignore other types for now). Now we allocate
char[6], expecting to be able to store two ints in it. "The most
stringent alignment requirement of any object type whose size is no
greater than the size of the array being created" is 4 bytes, so the
array only needs to be aligned on a multiple of 4, and may not be
properly aligned for an int.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"But for a pop culture junkie, cyberspace is the final frontier. Where
else can you find more pop, culture, and junk?" -- Diana Wichtel

---
[ comp.std.c++ is moderated.  To submit articles, try 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: wmm@fastdial.net
Date: 2000/11/28
Raw View
In article <3A240B97.E5349CC1@ihug.co.nz>,
  Ross Smith <ross.s@ihug.co.nz> wrote:
> wmm@fastdial.net wrote:
> >
> > In article <3A22D0CB.2478A6E5@ihug.co.nz>,
> >   Ross Smith <ross.s@ihug.co.nz> wrote:
> > > wmm@fastdial.net wrote:
> > > >
> > > > 5.3.4p10:
> > > >
> > > >     For arrays of char and unsigned char, the difference between
> > > >     the result of the new-expression and the address returned by
> > > >     the allocation function shall be an integral multiple of the
> > > >     most stringent alignment requirement (3.9) of any object
> > > >     type whose size is no greater than the size of the array
> > > >     being created. [Note: Because allocation functions are
> > > >     assumed to return pointers to storage that is appropriately
> > > >     aligned for objects of any type, this constraint on array
> > > >     allocation overhead permits the common idiom of allocating
> > > >     character arrays into which objects of other types will
later
> > > >     be placed. ]
> > >
> > > I take your point and agree I was wrong by the stated intent of
the
> > > standard, but a real nitpicker (who, me?) might argue that the
> > > requirement that "the difference ... shall be an integral
multiple of
> > > the most stringent alignment requirement" is not enough to
guarantee
> > > correct alignment. There is, as far as I can tell, no requirement
that
> > > the alignment of every type be a multiple of the alignment of
every
> > > smaller type, which would be necessary for the paragraph above to
work
> > > as intended.
> >
> > No, I think the wording is fine as written.  What it basically
> > says is that a buffer of size N must have sufficiently stringent
> > alignment to accommodate _any_ object whose size is N or less.
> > If, for instance, a short were required to begin on a 4-byte
> > boundary and a double could begin on any 2-byte boundary, the
> > result of "new char[sizeof(double)]" would be required to begin
> > (at least) on a 4-byte boundary because a short will fit into a
> > sizeof(double) buffer.
>
> No, you're still assuming that all alignments are multiples of each
> other. Say we had a strange machine where ints were on 3-byte
boundaries
> and floats on 4-byte (ignore other types for now). Now we allocate
> char[6], expecting to be able to store two ints in it. "The most
> stringent alignment requirement of any object type whose size is no
> greater than the size of the array being created" is 4 bytes, so the
> array only needs to be aligned on a multiple of 4, and may not be
> properly aligned for an int.

Okay, I see where you're going now.

There is something like an assumption that alignment requirements
are multiples of each other in the constraints on pointer casts
in 5.2.10p7 ("where the alignment requirements of T2 are no
stricter than those of T1") -- it assumes that a pointer to a
type with a strict alignment requirement can be represented by
a pointer to a type with a less-restrictive requirement, which
wouldn't necessarily be so in an architecture such as you posit.

To fix the 5.3.4p10 problem, I guess we'd need something like
"an integral multiple of the alignment requirements of every
object type whose size is no greater..."  I'm not sure it's
worth a defect report, though -- do you know of any real
architectures where the current wording would not be sufficient?

--
William M. Miller, wmm@fastdial.net
Vignette Corporation (www.vignette.com)


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: Ross Smith <ross.s@ihug.co.nz>
Date: 2000/11/28
Raw View
wmm@fastdial.net wrote:
>
> In article <3A240B97.E5349CC1@ihug.co.nz>,
>   Ross Smith <ross.s@ihug.co.nz> wrote:
> >
> > No, you're still assuming that all alignments are multiples of each
> > other. Say we had a strange machine where ints were on 3-byte
> boundaries
> > and floats on 4-byte (ignore other types for now). Now we allocate
> > char[6], expecting to be able to store two ints in it. "The most
> > stringent alignment requirement of any object type whose size is no
> > greater than the size of the array being created" is 4 bytes, so the
> > array only needs to be aligned on a multiple of 4, and may not be
> > properly aligned for an int.
>
> Okay, I see where you're going now.
>
> There is something like an assumption that alignment requirements
> are multiples of each other in the constraints on pointer casts
> in 5.2.10p7 ("where the alignment requirements of T2 are no
> stricter than those of T1") -- it assumes that a pointer to a
> type with a strict alignment requirement can be represented by
> a pointer to a type with a less-restrictive requirement, which
> wouldn't necessarily be so in an architecture such as you posit.

I agree that the authors of the standard seem to have been making the
same assumption in that paragraph, but again, I think a sufficiently
determined language lawyer could get away with it. If converting between
pointers of different alignments always gives you the _nearest_ multiple
of the target alignment (or either of the two if it's halfway between),
there-and-back conversions of the kind described there would work as
expected.

> To fix the 5.3.4p10 problem, I guess we'd need something like
> "an integral multiple of the alignment requirements of every
> object type whose size is no greater..."  I'm not sure it's
> worth a defect report, though -- do you know of any real
> architectures where the current wording would not be sufficient?

No. I've heard of one piece of big iron (I forget which -- one of the
early Crays?) that had 48-bit ints and 64-bit floats, but that was
because ints were stored in the mantissa part of an FP register, so I
expect all storage was 64-bit-aligned anyway. I've also heard of an old
video game CPU that had integers and pointers of mismatched sizes (I
forget the exact figures but it was something like 10 vs 14 bits), but I
doubt very much that it's still in use, or that it ever had a C (never
mind C++) compiler when it was.

I don't seriously think it's worth worrying about either; I'm just
engaging in the ancient and time-honoured Usenet tradition of merciless
nitpicking. :-)

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"But for a pop culture junkie, cyberspace is the final frontier. Where
else can you find more pop, culture, and junk?" -- Diana Wichtel

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ron Natalie <ron@sensor.com>
Date: Fri, 1 Dec 2000 07:40:44 GMT
Raw View

James.Kanze@dresdner-bank.com wrote:

> I thought he'd already posted an example.  Anyway, suppose that double
> requires an alignment of 8, and int an alignment of 6.  The most
> stringent alignment is 8, but not all addresses aligned for 8 will
> also be aligned for 6.

I guess the spec needs a better definition of "stringent"

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ron Natalie <ron@sensor.com>
Date: Fri, 1 Dec 2000 07:41:08 GMT
Raw View

James Kuyper wrote:
>
> Ron Natalie wrote:
> >
> > Ross Smith wrote:
> >
> > >
> > > How do you arrive at that? The standard only requires a multiple of the
> > > _most stringent_ alignment, not of _all_ of them. (I'll grant you the
> > > _intention_ was probably to require all of them, but that's not what it
> > > actually says.)
> > >
> > Now you've lost me.  If it is conforms to the MOST STRINGENT alignment
> > how can it not conform to the others?
>
> If the MOST STRINGENT alignment is not the least common multiple of ALL
> of the other alignments. In the example given the relevant alignements
> were 3 and 4. The most stringent alignement was 4. Therefore, a request
> for 6 bytes must be aligned on a multiple of 4, but needn't be aligned
> on a multiple of 3. That was almost certainly not the intent of the
> author.

The standard reads:

   For arrays of char and
   unsigned char, the difference between the result of the
   new-expression and the address returned by the
   allocation function shall be an integral multiple
   of the most stringent alignment requirement (3.9) of any
   object type whose size is no greater than the size
   of the array being created.

It's hard for me to understand how 4 is more stringent than 3.

---
[ comp.std.c++ is moderated.  To submit articles, try 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/12/01
Raw View
Ron Natalie wrote:
>
> James Kuyper wrote:
> >
> > Ron Natalie wrote:
> > >
> > > Ross Smith wrote:
> > >
> > > >
> > > > How do you arrive at that? The standard only requires a multiple of the
> > > > _most stringent_ alignment, not of _all_ of them. (I'll grant you the
> > > > _intention_ was probably to require all of them, but that's not what it
> > > > actually says.)
> > > >
> > > Now you've lost me.  If it is conforms to the MOST STRINGENT alignment
> > > how can it not conform to the others?
> >
> > If the MOST STRINGENT alignment is not the least common multiple of ALL
> > of the other alignments. In the example given the relevant alignements
> > were 3 and 4. The most stringent alignement was 4. Therefore, a request
> > for 6 bytes must be aligned on a multiple of 4, but needn't be aligned
> > on a multiple of 3. That was almost certainly not the intent of the
> > author.
>
> The standard reads:
>
>    For arrays of char and
>    unsigned char, the difference between the result of the
>    new-expression and the address returned by the
>    allocation function shall be an integral multiple
>    of the most stringent alignment requirement (3.9) of any
>    object type whose size is no greater than the size
>    of the array being created.
>
> It's hard for me to understand how 4 is more stringent than 3.

It's hard for me to understand how 4 is not more stringent than 3. To
me, the more stringent alignment is the one that places greater
restrictions on the address. An alignment requirement of N allows only 1
out of every N addresses, so the most stringent alignment is the one
with the largest value. What definition of stringent are you using?

However, that's irrelevant. If you're saying that 3 is the most
stringent requirement, than that would mean that an allocation of 6
bytes would be allowed to return a pointer aligned to a multiple of 3,
but NOT necessarily to a multiple of 4. The problem is that the
alignment of the returned pointer should depend upon the alignment
requirements of all object types that could fit in that space, and not
on the alignment of any any one type.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://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/12/04
Raw View
Ron Natalie wrote:
>
> James.Kanze@dresdner-bank.com wrote:
>
> > I thought he'd already posted an example.  Anyway, suppose that double
> > requires an alignment of 8, and int an alignment of 6.  The most
> > stringent alignment is 8, but not all addresses aligned for 8 will
> > also be aligned for 6.
>
> I guess the spec needs a better definition of "stringent"

Can you come up with a definition of stringent that makes "The most
stringent alignment requirement of any object type whose size is no
greater than the size of the array being created" be anything larger
than 8 for an allocation of 8 bytes on such an implementation?  The
problem lies not in the word "stringent" itself, but in the words around
"stringent" which make the alignment of one type, and only one type,
relevant. Suggested change to 5.3.4:

"... For arrays of char and unsigned char, the difference between the
result of the new-expression and the address returned by the allocation
function shall be an integral multiple of the alignment requirements
(3.9) of every object type whose size is no greater than the size of the
array being created. ..."

As has already been pointed out, 5.2.10p7 and p9 make the same
assumption, and if this is changed, then so should those two paragraphs,
perhaps by replacing "no stricter than" with "an integer multiple 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://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Bryan Goring <nbgoring@home.com>
Date: Mon, 27 Nov 2000 00:27:31 GMT
Raw View
I am trying to understand how the delete operator knows how many bytes
have been allocated to a particular pointer.

Lets say I allocate a series of bytes with new ala

char* buf = new char[1024];

Following this I assign this pointer to a structure that is going to
maintain offsets to some data fields e.g.

typedef struct MTag {
 int size;
 int offset1;
 int offset2;
} M;

M* m = (M*)buf;

Now I do some operations where memory is copied to the buffer at the
relevant offsets and the m pointer
is used to set these offsets as in

m->offset1 = sizeof(M);
m->offset2 = m->offset1 + strlen(firstString);

This pointer m is now assigned as some attribute of an object that
during destruction is deallocated via

class SomeObject() {
 .
 .
 private:
 M* _m;
};

SomeObject::~SomeObject() {
 delete(_m);
}

My question is, how does the runtime know to delete the original 1024
bytes (if indeed it does) rather than
the 12 bytes associated with the M structure type?

Bryan Goring
nbgoring@home.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: James Kuyper <kuyper@wizard.net>
Date: Mon, 27 Nov 2000 01:26:59 GMT
Raw View
Bryan Goring wrote:
>
> I am trying to understand how the delete operator knows how many bytes
> have been allocated to a particular pointer.
>
> Lets say I allocate a series of bytes with new ala
>
> char* buf = new char[1024];
...
[move buf into _m]
>  delete(_m);
...
> My question is, how does the runtime know to delete the original 1024
> bytes (if indeed it does) rather than
> the 12 bytes associated with the M structure type?

That's up to the implementation. There are several possibilities:
1. Use a lookup-table mapping pointer values to the amount of space
allocated.
2. Allocations are always rounded up the next power of two; allocations
for different powers of two are always allocated from different memory
pools. By examining the pointer, the implementation can determine which
memory pool it was allocated from, and therefore what the adjusted
allocation size was (the adjusted size is the only one that matters; the
original size is irrelevant).
3. The single most common implementation, however, is store the number
of bytes of memory allocated in a piece of memory at a negative offset
from the pointer returned by new. Then delete looks at the same negative
offset to determine the number of bytes to release.
4. Heavy pointers - a pointer contains not only the address of the
object pointed at, but also the start and end of the particular
allocation it was derived from.

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Ross Smith <ross.s@ihug.co.nz>
Date: 2000/11/27
Raw View
Bryan Goring wrote:
>
> I am trying to understand how the delete operator knows how many bytes
> have been allocated to a particular pointer.

I'm afraid you've badly misunderstood the behaviour of delete, as well
as several other aspects of C++.

> Lets say I allocate a series of bytes with new ala
>
> char* buf = new char[1024];
>
> Following this I assign this pointer to a structure that is going to
> maintain offsets to some data fields e.g.
>
> typedef struct MTag {
>  int size;
>  int offset1;
>  int offset2;
> } M;

The old C trick of declaring a struct in a typedef is unnecessary in
C++.

> M* m = (M*)buf;

This is non-portable. Casting a pointer from one arbitrary type to
another is not required to produce a valid result. (For example, the
space you allocated might not be correctly aligned for an M, since you
lied to the compiler by claiming you were only going to store chars in
it.)

> Now I do some operations where memory is copied to the buffer at the
> relevant offsets and the m pointer
> is used to set these offsets as in
>
> m->offset1 = sizeof(M);
> m->offset2 = m->offset1 + strlen(firstString);

While I don't know exactly what you were intending to achieve here, I
strongly suspect that last bit should read "strlen(firstString) + 1". In
any case, playing with character arrays, while still legal in C++, is
almost never a good idea. If you want to do anything with strings, use
the standard string type.

> This pointer m is now assigned as some attribute of an object that
> during destruction is deallocated via
>
> class SomeObject() {
>  .
>  .
>  private:
>  M* _m;
> };

Don't use leading underscores. Many names beginning with an underscore
are reserved for the implementation; the exact rules for which names are
reserved under various circumstances are complicated, and the usual
advice is not to bother memorising them and just avoid leading
underscores everywhere.

> SomeObject::~SomeObject() {
>  delete(_m);
> }
>
> My question is, how does the runtime know to delete the original 1024
> bytes (if indeed it does) rather than
> the 12 bytes associated with the M structure type?

It doesn't. At least the way you've used it.

You're deleting memory through a pointer to a different type to the one
used in new. This invokes undefined behaviour. You should be deleting
the original buf pointer, and you should be using the array form of
delete (i.e. "delete[] buf;", not "delete buf;").

The system knows how much space to free when you call delete[] because
it kept some kind of record of it when you called new[]. There are
several ways this can be implemented; probably the most common is simply
to allocate a few bytes of extra space and keep a byte count or object
count in it. (The reason the user is required to match new/delete vs
new[]/delete[] correctly is to avoid having to add this overhead to all
dynamically allocated objects.) Another approach sometimes used is a
memory manager that reserves parts of the address space for blocks of
particular sizes; when memory is allocated, it rounds it up to the next
standard block size and allocates a page from the relevant area; when
it's freed, it can deduce the block size to free from the address.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
 "There are many technical details that make Linux attractive to the
 sort of people to whom technical details are attractive."   -- Suck

---
[ comp.std.c++ is moderated.  To submit articles, try 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: "Richard Parkin" <rparkin@nospam.msi-eu.com>
Date: 2000/11/27
Raw View
"Bryan Goring" <nbgoring@home.com> wrote in message
news:3A21514E.9C833E9B@home.com...
> I am trying to understand how the delete operator knows how many bytes
> have been allocated to a particular pointer.
>
> Lets say I allocate a series of bytes with new ala
>
> char* buf = new char[1024];

[move buf into _m]

>  delete(_m);

> My question is, how does the runtime know to delete the original 1024
> bytes (if indeed it does) rather than
> the 12 bytes associated with the M structure type?

James has already pointed out several ways it can achieve this.

However, by deleting via a M* an array allocated as a char*, it invokes
undefined behavior - incorrect type, and delete rather than delete[].

Ric


---
[ comp.std.c++ is moderated.  To submit articles, try 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/11/27
Raw View
In article <3A21514E.9C833E9B@home.com>, Bryan Goring
<nbgoring@home.com> writes

Actually this should have been posted to comp.lang.c++.moderated as it
is about the use of C++ not about the C++ Standard.

>I am trying to understand how the delete operator knows how many bytes
>have been allocated to a particular pointer.

Why should it, it just tells the heap manager to take back the block of
memory it allocated which is why you must always use the address
returned by the appropriate allocator.

>
>Lets say I allocate a series of bytes with new ala
>
>char* buf = new char[1024];

This is not the way to obtain raw memory in C++, try:

void * buf = operator new(1024);

Or even use malloc.
>
>Following this I assign this pointer to a structure that is going to
>maintain offsets to some data fields e.g.
>
>typedef struct MTag {
> int size;
> int offset1;
> int offset2;
>} M;
>
>M* m = (M*)buf;

And that will work fine to convert raw memory to typed memory, but a
static_cast<> will work for void* and is preferred because it is more
explicit.

>
>Now I do some operations where memory is copied to the buffer at the
>relevant offsets and the m pointer
>is used to set these offsets as in
>
>m->offset1 = sizeof(M);
>m->offset2 = m->offset1 + strlen(firstString);
>
>This pointer m is now assigned as some attribute of an object that
>during destruction is deallocated via
>
>class SomeObject() {
> .
> .
> private:
> M* _m;
>};
>
>SomeObject::~SomeObject() {
> delete(_m);

And that is WRONG, because you are not using the original pointer (you
changed its type, and worse still you used the wrong delete, and even
worse you cannot use the correct delete because _m is not a pointer to
an array of char.


However, assuming the some-object 'owns' the buffer and you had created
it as I suggest, you could write:
operator delete(static_cast<void*>(_m));

but why not:

operator delete(buf);
>}
>
>My question is, how does the runtime know to delete the original 1024
>bytes (if indeed it does) rather than
>the 12 bytes associated with the M structure type?
>
>Bryan Goring
>nbgoring@home.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.     ]
>

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: wmm@fastdial.net
Date: 2000/11/27
Raw View
In article <3A21514E.9C833E9B@home.com>,
  Bryan Goring <nbgoring@home.com> wrote:
> I am trying to understand how the delete operator knows how many bytes
> have been allocated to a particular pointer.
>
> Lets say I allocate a series of bytes with new ala
>
> char* buf = new char[1024];
>
> Following this I assign this pointer to a structure that is going to
> maintain offsets to some data fields e.g.
>
> typedef struct MTag {
>  int size;
>  int offset1;
>  int offset2;
> } M;
>
> M* m = (M*)buf;
>
> Now I do some operations where memory is copied to the buffer at the
> relevant offsets and the m pointer
> is used to set these offsets as in
>
> m->offset1 = sizeof(M);
> m->offset2 = m->offset1 + strlen(firstString);
>
> This pointer m is now assigned as some attribute of an object that
> during destruction is deallocated via
>
> class SomeObject() {
>  .
>  .
>  private:
>  M* _m;
> };
>
> SomeObject::~SomeObject() {
>  delete(_m);
> }
>
> My question is, how does the runtime know to delete the original 1024
> bytes (if indeed it does) rather than
> the 12 bytes associated with the M structure type?

This code has undefined behavior -- i.e., an implementation can
do anything it wants to (including doing what you expect).

According to the Standard (5.3.5), the only case in which the
type of the pointer being deleted can be different from the
type that was returned by the "new" expression is when you
delete via a base class of the allocated object (and the base
class must have a virtual destructor).

To make this well-defined, you'd need to do

        delete [] (char*) _m;

(Note the use of "[]" in the delete expression, which is
required because you allocated an array in the first place.)

--
William M. Miller, wmm@fastdial.net
Vignette Corporation (www.vignette.com)


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: James.Kanze@dresdner-bank.com
Date: 2000/11/27
Raw View
In article <3A21514E.9C833E9B@home.com>,
  Bryan Goring <nbgoring@home.com> wrote:
> I am trying to understand how the delete operator knows how many
> bytes have been allocated to a particular pointer.

That pretty much depends on the implementation.

> Lets say I allocate a series of bytes with new ala

> char* buf = new char[1024];

> Following this I assign this pointer to a structure that is going to
> maintain offsets to some data fields e.g.

> typedef struct MTag {
>  int size;
>  int offset1;
>  int offset2;
> } M;

> M* m = (M*)buf;

Hmmm.  I'm not sure that this is legal, although I cannot think of an
implementation where it would fail.  The normal way to do the cast in
C++ is:

    M* m = new ( buf ) M ;

In the case of a POD, like M, however, I can't think of how this would
be different.  On the other hand, it avoids a nasty reinterpret_cast.

> Now I do some operations where memory is copied to the buffer at the
> relevant offsets and the m pointer is used to set these offsets as
> in

> m->offset1 = sizeof(M);
> m->offset2 = m->offset1 + strlen(firstString);

> This pointer m is now assigned as some attribute of an object that
> during destruction is deallocated via

> class SomeObject() {
>  .
>  .
>  private:
>  M* _m;
> };

> SomeObject::~SomeObject() {
>  delete(_m);

This is undefined behavior, for two reasons:
  - the memory was allocated with new[], and thus must be deleted with
    delete[], and
  - the type of the pointer in the delete is different from the type
    returned by the new expression.
To be correct, you would have to write:

    delete[]( reinterpret_cast< char* >( _m ) ) ;

> }

> My question is, how does the runtime know to delete the original
> 1024 bytes (if indeed it does) rather than the 12 bytes associated
> with the M structure type?

There are many different solutions.  Most involve storing information
before the returned pointer, although are able to determine the
information uniquely from the pointer itself.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


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: wmm@fastdial.net
Date: 2000/11/27
Raw View
In article <3A21CD09.E06AEF19@ihug.co.nz>,
  Ross Smith <ross.s@ihug.co.nz> wrote:
> Bryan Goring wrote:
> >
> > Lets say I allocate a series of bytes with new ala
> >
> > char* buf = new char[1024];
> >
> > Following this I assign this pointer to a structure that is going to
> > maintain offsets to some data fields e.g.
> >
> > typedef struct MTag {
> >  int size;
> >  int offset1;
> >  int offset2;
> > } M;
> > M* m = (M*)buf;
>
> This is non-portable. Casting a pointer from one arbitrary type to
> another is not required to produce a valid result. (For example, the
> space you allocated might not be correctly aligned for an M, since you
> lied to the compiler by claiming you were only going to store chars in
> it.)

No, actually, this part is okay.  If the buffer were declared
as anything other than char or unsigned char, the alignment is
not guaranteed, but there's a special allowance for this kind
of usage in 5.3.4p10:

    For arrays of char and unsigned char, the difference between
    the result of the new-expression and the address returned by
    the allocation function shall be an integral multiple of the
    most stringent alignment requirement (3.9) of any object
    type whose size is no greater than the size of the array
    being created. [Note: Because allocation functions are
    assumed to return pointers to storage that is appropriately
    aligned for objects of any type, this constraint on array
    allocation overhead permits the common idiom of allocating
    character arrays into which objects of other types will later
    be placed. ]

--
William M. Miller, wmm@fastdial.net
Vignette Corporation (www.vignette.com)


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/11/27
Raw View
In article <3A21CD09.E06AEF19@ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>The system knows how much space to free when you call delete[] because
>it kept some kind of record of it when you called new[]. There are
>several ways this can be implemented; probably the most common is simply
>to allocate a few bytes of extra space and keep a byte count or object
>count in it.

Actually, the important issue concerns the number of objects that need
destruction before the memory is deallocated. Many systems do not need
to know how much raw memory is being deallocated because the 'heap
manager' knows the size of the block it allocated and will take it all
back.


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: Ross Smith <ross.s@ihug.co.nz>
Date: 2000/11/27
Raw View
wmm@fastdial.net wrote:
>
> In article <3A21CD09.E06AEF19@ihug.co.nz>,
>   Ross Smith <ross.s@ihug.co.nz> wrote:
> >
> > This is non-portable. Casting a pointer from one arbitrary type to
> > another is not required to produce a valid result. (For example, the
> > space you allocated might not be correctly aligned for an M, since you
> > lied to the compiler by claiming you were only going to store chars in
> > it.)
>
> No, actually, this part is okay.  If the buffer were declared
> as anything other than char or unsigned char, the alignment is
> not guaranteed, but there's a special allowance for this kind
> of usage in 5.3.4p10:
>
>     For arrays of char and unsigned char, the difference between
>     the result of the new-expression and the address returned by
>     the allocation function shall be an integral multiple of the
>     most stringent alignment requirement (3.9) of any object
>     type whose size is no greater than the size of the array
>     being created. [Note: Because allocation functions are
>     assumed to return pointers to storage that is appropriately
>     aligned for objects of any type, this constraint on array
>     allocation overhead permits the common idiom of allocating
>     character arrays into which objects of other types will later
>     be placed. ]

I take your point and agree I was wrong by the stated intent of the
standard, but a real nitpicker (who, me?) might argue that the
requirement that "the difference ... shall be an integral multiple of
the most stringent alignment requirement" is not enough to guarantee
correct alignment. There is, as far as I can tell, no requirement that
the alignment of every type be a multiple of the alignment of every
smaller type, which would be necessary for the paragraph above to work
as intended.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
 "There are many technical details that make Linux attractive to the
 sort of people to whom technical details are attractive."   -- Suck

---
[ comp.std.c++ is moderated.  To submit articles, try 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: Tue, 28 Nov 2000 00:23:35 GMT
Raw View
Francis Glassborow wrote:
>
> In article <3A21514E.9C833E9B@home.com>, Bryan Goring
> <nbgoring@home.com> writes
...
> >Lets say I allocate a series of bytes with new ala
> >
> >char* buf = new char[1024];
>
> This is not the way to obtain raw memory in C++, try:
>
> void * buf = operator new(1024);
>
> Or even use malloc.

I agree with you that the alternatives will work. However, what is wrong
with the original version?

---
[ comp.std.c++ is moderated.  To submit articles, try 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.     ]