Topic: Standard operation of new and delete o
Author: Stephen.Clamage@eng.sun.com (Steve Clamage)
Date: 1997/03/31 Raw View
In article roo@mulga.cs.mu.OZ.AU, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
writes:
>
>The solution to your dilemma comes from a different part of the C++
>draft working paper, which says that an implementation must not
>assume anything about replacable functions other than their required
>behaviour. Hmmm, well I _thought_ there was such a statement in
>the draft -- but I can't seem to find it. That statement, if present,
>would render the IBM implementation non-conforming, presuming that
>the functions calling delete with an invalid address are part of its
>standard C++ library. (If the functions that have that undesirable
>behaviour are part of a non-standard library, then there is nothing that
>the C++ standard could do about it.)
>
>Does anyone know if my recollection is correct?
>Was there such a statement in a previous draft?
>It is still there? If so, where, and if not, why not?
I've excerpted some paragraphs from the draft standard. Taken together,
they say that you can replace operator new, and the replacement need
only meet the requirements laid out in the standard. If an
implementation requires additional or different behavior, it would be
non-conforming. The same goes for operator delete.
17.1 Definitions
- default behavior: A description of *replacement function* and *handler
function* semantics. Any specific behavior provided by the implementation,
within the scope of the *required behavior*.
- replacement function: A *non-reserved function* whose definition is
provided by a C++ program. Only one definition for such a function
is in effect for the duration of the program's execution, as the result
of creating the program (2.1) and resolving the definitions of all
translation units (3.5).
- required behavior: A description of *replacement function* and *handler
function* semantics, applicable to both the behavior provided by the
implementation and the behavior that shall be provided by any function
definition in the program. If a function defined in a C++ program
fails to meet the required behavior when it executes, the behavior
is undefined.
17.2.1.3 Specifications
4 For non-reserved replacement and handler functions, Clause 18 specifies
two behaviors for the functions in question: their required and default
behavior. The default behavior describes a function definition provided
by the implementation. The required behavior describes the semantics of a
function definition provided by either the implementation or a C++
program. Where no distinction is explicitly made in the description,
the behavior described is the required behavior.
17.3.3.4 Replacement functions
2 A C++ program may provide the definition for any of eight dynamic
memory allocation function signatures declared in header <new> (3.7.3, 18):
[ lists the eight forms of operators new and delete]
17.3.3.6 Other functions
1 In certain cases (replacement functions, handler functions, operations
on types used to instantiate standard library template components), the
C++ Standard library depends on components supplied by a C++ program.
If these components do not meet their requirements, the Standard places
no requirements on the implementation
[ And finally, an example specification. ]
18.4.1.1 Single-object forms
void* operator new(std::size_t size) throw(bad_alloc);
1 Effects: The allocation function (3.7.3.1) called by a new-expression
(5.3.4) to allocate size bytes of storage suitably aligned to represent
any object of that size.
2 Replaceable: a C++ program may define a function with this function
signature that displaces the default version defined by the C++
Standard library.
3 Required behavior: Return a pointer to dynamically allocated storage
(3.7.3), or else throw a bad_alloc exception.
---
Steve Clamage,
stephen.clamage@eng.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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Stephen.Clamage@eng.sun.com (Steve Clamage)
Date: 1997/03/31 Raw View
In article 746@oz.net, Kevin Mullin <kmullin@oz.net> writes:
>Steve Clamage wrote:
>
> The standard could mandate particular behavior in the presence of an
> invalid delete. That in turn would require that implementations always
> validate pointer expressions passed to 'delete', something that is
> very expensive to do. (Some languages do make that requirement, and
> run-time efficiency suffers.)
>
>For my own education, I'd like to know what this overhead would be.
Consider this function, where T is some type:
void f(T* tp) { delete tp; }
What types of run-time errors are possible, not in general detectable
at compile time? I'll name the ones I can think of offhand -- the list
might not be complete. (It doesn't really matter -- this list is bad
enough.)
1. tp might not point to an object allocated by a new-expression.
2. tp might point to an array of objects, allocated with array-new.
3. tp might point to an object allocated as a different type, but
a type which is not a class derived from T.
4. tp might point to an object allocated as a type derived from T,
but T does not have a virtual destructor.
5. tp might point to an object appropriately allocated for this
delete expression, but the object has already been deleted.
This is a similar to #1.
6. tp might point to an object appropriately allocated for this
delete expression, but the object has already been deleted
and the address has been reused for an object of a
different type. This is a similar to #3.
The list for an array-delete-expression is similar.
If you are going to catch all these errors, you have to keep track of
every address that was allocated plus the type of object allocated. You
have to keep a symbol table around for run-time access so you can make
the checks suggested by #3 and #4. Every allocation has to add to this
list, and every delete has to search the list for a matching entry,
perform the checks suggested above, and remove the entry.
The extra time and space overhead for these operations is considerable.
The proof of my claim is found in those implementations and third-party
products that perform such checks. The performance difference when
the checks are enabled is not just measureable, it is often dramatic.
---
Steve Clamage, stephen.clamage@eng.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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: David Vandevoorde <daveed@vandevoorde.com>
Date: 1997/04/01 Raw View
Steve Clamage wrote:
> I've excerpted some paragraphs from the draft standard. Taken
> together,
> they say that you can replace operator new, and the replacement need
> only meet the requirements laid out in the standard. If an
> implementation requires additional or different behavior, it would be
> non-conforming. The same goes for operator delete.
]
Somewhere in Chapter 5 it says that a pointer returned by a
new-expression is distinct from the pointer to any other
object (somewhere in [expr.new]; don't have a WP handy).
Now, does that mean this must be the case for replacement
allocation functions as well? I would say `yes' for non-placement
replacements (including class-specific operator-news). For
placement versions the situation is more complex, I think:
the new(nothrow) X; presumably returns 0 or fresh memory.
OTOH, new(&x) X; by definition returns an aliased piece of
memory (although one could argue that it might not point to
a live object).
Any comments on this issue?
Daveed
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/02 Raw View
David Vandevoorde <daveed@vandevoorde.com> writes:
|> Steve Clamage wrote:
|> > I've excerpted some paragraphs from the draft standard. Taken
|> > together,
|> > they say that you can replace operator new, and the replacement need
|> > only meet the requirements laid out in the standard. If an
|> > implementation requires additional or different behavior, it would be
|> > non-conforming. The same goes for operator delete.
|> ]
|> Somewhere in Chapter 5 it says that a pointer returned by a
|> new-expression is distinct from the pointer to any other
|> object (somewhere in [expr.new]; don't have a WP handy).
|>
|> Now, does that mean this must be the case for replacement
|> allocation functions as well? I would say `yes' for non-placement
|> replacements (including class-specific operator-news). For
|> placement versions the situation is more complex, I think:
|> the new(nothrow) X; presumably returns 0 or fresh memory.
|> OTOH, new(&x) X; by definition returns an aliased piece of
|> memory (although one could argue that it might not point to
|> a live object).
|>
|> Any comments on this issue?
Probably that you have to use common sense when reading the draft:-).
Seriously, given the following:
union X
{
MaxAlign dummyForAlignment ;
unsigned char buffer[ sizeof( T ) ] ;
} rawMemory ;
T* pt( new ( rawMemory.buffer ) T ) ;
I would argue that the fact of executing the constructor on buffer
effectively causes the object (of type X) at rawMemory to cease to
exist, see 3.8: "The lifetime of an object of type T ends when [...]
the storage which the object occupies is reused or released." If T has
a non-trivial constructor, calling it definitly "reuses" the memory; I
think that any reasonable interpretation would say that calling
placement new on the given location always "reuses" the memory,
non-trivial constructor or not. Thus:
T* pt( new T ) ;
new ( pt ) char[ sizeof( T ) ] ;
delete pt ; // Undefined behavior, the object of type
// T no longer exists.
Of course, if any object at the given location ceases to exist as a
result of calling placement new, the returned pointer points to no other
object, by definition.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/03 Raw View
David Vandevoorde <daveed@vandevoorde.com> writes:
>
>|> Somewhere in Chapter 5 it says that a pointer returned by a
>|> new-expression is distinct from the pointer to any other
>|> object (somewhere in [expr.new]; don't have a WP handy).
The only place I could spot is where it is talking about `new T[n]' for
the `n == 0' case, in 5.3.4[expr.new]/8. I think that is just sloppy
wording. In the case of `new (nothrow) T[n]', which is also covered by
the same wording, these requirements are impossible to adhere to
without resorting to the general escape clause in 1.3[intro.compliance]/2
``within its resource limits'', because they require it to return a
distinct non-null pointer every time; returning a null pointer on
failure isn't allowed.
Apart from 5.3.4[expr.new]/8, which applies only to the case of allocating
arrays with zero elements, it just says that
5.3.4 [expr.new]
13 The allocation function shall either return null or a
pointer to a block of memory in which space for the
object shall have been reserved
I think the meaning of the word "reserved" is sufficient to guarantee
that in general successive calls to an allocation function must not
return the same address, though in general not sufficient to guarantee
that the pointer is "distinct from any other object", although in the
case of the `void *' placement operator new, it must be the _callers_
responsibility to ensure that the address passed (and returned)
is appropriate reserved.
James Kanze writes:
> T* pt( new T ) ;
> new ( pt ) char[ sizeof( T ) ] ;
> delete pt ; // Undefined behavior, the object of type
> // T no longer exists.
Actually that is undefined behaviour at the second line already,
because array new may need extra space to store the element count.
--
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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/04/03 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
: Probably that you have to use common sense when reading the draft:-).
Ok, let's test our common sense.
Is this legal?
class Test{
public:
static void* operator new(size_t, void*){return T_;}
static void* operator new(size_t size){return ::operator new(size);}
private:
static void* const T_;
};
void* const Test::T_ = ::operator new(sizeof(Test));
Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/08 Raw View
Oleg Zabluda <zabluda@math.psu.edu> writes:
|> James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
|> : Probably that you have to use common sense when reading the draft:-).
|>
|> Ok, let's test our common sense.
|>
|> Is this legal?
|>
|> class Test{
|> public:
|> static void* operator new(size_t, void*){return T_;}
|> static void* operator new(size_t size){return ::operator new(size);}
|> private:
|> static void* const T_;
|> };
|>
|> void* const Test::T_ = ::operator new(sizeof(Test));
I think so, but I also think that anyone who would actually write code
like this should be shot. (Common sense tells me that it is very bad
code.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]