using delete expression on global operator new allocated memory

Discussion in 'C++' started by dizzy, Apr 30, 2008.

  1. dizzy

    dizzy Guest

    Hi

    I wonder if this code is standard conformant and should work on all
    conformant implementations (for some type T):

    1: void* mem = ::eek:perator new(sizeof(T));
    2: T* p = new(mem) T(args...);
    3: delete p;

    line 2 I know it should be fine because global operator new should return
    memory aligned for any type. The thing I wonder about is line 3. Should
    this always work?

    PS: the code might seem silly, it is needed because I need to decouple the
    point of storage type used (which on 2 different codepaths can be on stack
    or dynamic) from the point of actual initialization of the object and its
    arguments (thus I need to use placement new); another solution I am aware
    of whould be using some kind of "factory functors" (like the ones in boost)
    but that would require for me to use template functions which is what I
    want to avoid in the first place

    --
    Dizzy
    dizzy, Apr 30, 2008
    #1
    1. Advertising

  2. dizzy

    Krice Guest

    On 30 huhti, 13:07, dizzy <> wrote:
    > PS: the code might seem silly


    It is silly.
    Krice, Apr 30, 2008
    #2
    1. Advertising

  3. dizzy

    James Kanze Guest

    On Apr 30, 12:07 pm, dizzy <> wrote:

    > I wonder if this code is standard conformant and should work on all
    > conformant implementations (for some type T):


    > 1: void* mem = ::eek:perator new(sizeof(T));
    > 2: T* p = new(mem) T(args...);
    > 3: delete p;


    > line 2 I know it should be fine because global operator new
    > should return memory aligned for any type. The thing I wonder
    > about is line 3. Should this always work?


    I think so, but I think the point is vague enough that I'd avoid
    counting on it. The usual rule is to separate destruction and
    deallocation anytime you've separated allocation and
    initialization. In other words, you sould probably replace 3
    with:

    p->~T() ;
    ::eek:perator delete( p ) ;

    > PS: the code might seem silly, it is needed because I need to
    > decouple the point of storage type used (which on 2 different
    > codepaths can be on stack or dynamic) from the point of actual
    > initialization of the object and its arguments (thus I need to
    > use placement new);


    I'm not sure I understand this. If the object is on the stack,
    it will have been constructed where it was declared, and will be
    destructed when it goes out of scope. So you can't use
    placement new on it later, and you can't explicitly delete it
    in any way.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 2, 2008
    #3
  4. dizzy

    dizzy Guest

    James Kanze wrote:

    > I think so, but I think the point is vague enough that I'd avoid
    > counting on it. The usual rule is to separate destruction and
    > deallocation anytime you've separated allocation and
    > initialization. In other words, you sould probably replace 3
    > with:
    >
    > p->~T() ;
    > ::eek:perator delete( p ) ;


    That doesn't work the way I do things (explanation below).

    > I'm not sure I understand this. If the object is on the stack,
    > it will have been constructed where it was declared, and will be
    > destructed when it goes out of scope. So you can't use
    > placement new on it later, and you can't explicitly delete it
    > in any way.


    But it exists in a possible call algorithm. So I will give more details
    about the code.

    Supose I have a hierarchy of user defined types, DerivedX (with X being from
    1 to 3) inherited from Base. The contents of a DerivedX at some point it is
    serialized somehow (say by first storing some kind of numeric value that
    associates the type stored and then the contents of the type). When I do
    deserialization obviously I need to read that value and then deserialize
    the actual type that I know follows in the input stream by using a ctor of
    the deserialized type that receives various arguments which arguments are
    first deserialized. I cannot just make a ctor version for each
    deserializable type that takes the stream type as argument and it will
    construct by deserialization from the stream and I cannot do something like
    overloading some operator<< on my stream types because there are many ways
    the objects are serialized/deserialized and they don't all depend on the
    stream type used (or making such stream types for each way would be
    pointless). So each way to deserialize has an API that will do it and
    considering one such way/API it should be able to provide 2 ways to do it:

    - one way, more straightforward and OOP (especially since all are inherited
    from a common base) is to have something like this:
    auto_ptr<Node> load(InputStream& is);

    Which obviously will read the type, will switch/case on it and then will
    deserialize the arguments needed for the ctor and then do something like
    return auto_ptr<Node>(new DerivedX(args...)); (where X will be dependent on
    the read numeric value that associates the serialized type)

    While fine from an OOP perspective this code fails in many other aspects
    because it will "lose" the actual type it was dereferenced and will return
    a (smart) pointer to the Base class thus forcing the callers to use some
    method (say a Visitor aproach) to identify the type again and perform
    actual work on the specific type. So then I said, I should have another API
    that does not lose the type.

    - the second way to perform object deserialization is to have a load like
    this:
    template<typename Function>
    void load(InputStream& is, Function func);

    In this second case, "load" will read again (from the stream) the numeric
    value that identifies the serialized type, then again will deserialize the
    arguments specific to this type and then will create locally (on stack) an
    object of the specific type using the deserialized arguments and will call
    func(thatobject) (so Function needs to have an operator() taking each
    possible obeject type). This is like a callback algorithm but avoiding the
    costs of using boost::function (or other such generic functor) because the
    callback happens with normal function call resolved at compile time and
    will also avoid a costly Visitor aproach to get the type lost from the
    first "load" version.

    In both "load" versions I need to read the numeric value, switch/case on it
    and then deserialize the arguments specific to the type and then construct
    the type from those arguments. Using the original question method I could
    decouple the reading of arguments/construction from the actual object
    storage without having the functions that do the actual read be templates
    (which I want to avoid) but they could just be something like:
    Derived0*
    loadDerived0(InputStream& is, void* where) {
    // deserialize specific Derived0 arguments
    return new(where) Derived0(args...);
    }

    The callers of these functions can either come from the codepath with
    the "functor" argument, in which case they allocated properly aligned
    storage on the stack and they will call the functor with argument on the
    initialized object and then get rid of it or they come from the codepath
    with the load returning auto_ptr<Base> in which case they will allocate
    memory aligned for anything with ::eek:perator new(sizeof(DerivedX)); and will
    return an auto_ptr to it. And as such at some point auto_ptr will call
    delete on the ::eek:perator new returned memory which I need to know if it is
    valid code.

    --
    Dizzy
    dizzy, May 2, 2008
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. alan
    Replies:
    3
    Views:
    2,749
    Sharad Kala
    Feb 18, 2004
  2. Replies:
    5
    Views:
    608
    Matt Wharton
    Dec 9, 2004
  3. Jef Driesen
    Replies:
    1
    Views:
    489
    Gernot Frisch
    Jan 19, 2005
  4. Robert Potthast
    Replies:
    0
    Views:
    291
    Robert Potthast
    Aug 31, 2005
  5. Alex Vinokur
    Replies:
    3
    Views:
    491
    Zoltan Juhasz
    Jun 15, 2012
Loading...

Share This Page