Is const_cast ok in marshalling code?

Discussion in 'C++' started by coal@mailvault.com, Feb 17, 2008.

  1. Guest

    I've been thinking about how to build(receive) an object from a stream
    if the object's type has a const data member. While it would be great
    to have ctors that read from a stream, I think const data members are
    a difficult obstacle to making progress in that direction. Another
    option would be to use an ordinary function called Receive. Say we
    have this class:

    class Cd {
    int const az_;

    public:
    int Send(Buffer*, int = 0) const;
    int Receive(Buffer*);
    };

    The code I'm thinking about using with Receive is:

    int
    Cd::Receive(Buffer* buf)
    {
    if (!buf->Give(const_cast<int*>(&az_), sizeof(int))) {
    buf->ews_.SetErrorWords(1, __FILE__, __LINE__);
    return 0;
    }
    return 1;
    }

    (*Buffer is here http://home.seventy7.com/misc/Buffer.hh.)

    That seems fine to me. However, in this thread, http://preview.tinyurl.com/2yw4aa,
    Eugene Gershnik wrote,

    "No this is not what I have meant. What I did mean was that if you
    need to interoprate with const-less library that you know
    won't change the data you can cast away const on the boundary....
    This and implementing non-const function in terms of const one are the
    only acceptable uses of const_cast."
    (It helps if you put a comma after the word data.)

    I guess the const_cast above wouldn't be what he considers an
    acceptable use. Is that rule commonly held? Any ideas on how to
    improve the implementation?

    Thanks.

    Brian Wood
    Ebenezer Enterprises
    www.webebenezer.net

    If you are in the United States illegally, you need to leave.
     
    , Feb 17, 2008
    #1
    1. Advertising

  2. * :
    > [Is const_cast ok in marshalling code?]


    No.

    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Feb 17, 2008
    #2
    1. Advertising

  3. Ian Collins Guest

    wrote:
    > I've been thinking about how to build(receive) an object from a stream
    > if the object's type has a const data member. While it would be great
    > to have ctors that read from a stream, I think const data members are
    > a difficult obstacle to making progress in that direction. Another
    > option would be to use an ordinary function called Receive. Say we
    > have this class:
    >

    If an object is to be built by anything other than its constructor, it
    can't have a const member.

    Why do you want one?

    --
    Ian Collins.
     
    Ian Collins, Feb 17, 2008
    #3
  4. Guest

    On Feb 16, 11:41 pm, "Alf P. Steinbach" <> wrote:
    > * :
    >  > [Is const_cast ok in marshalling code?]
    >
    > No.
    >
    > Cheers, & hth.,
    >


    It helps, but why do you say that?

    Brian Wood
     
    , Feb 17, 2008
    #4
  5. Guest

    On Feb 17, 12:09 am, Ian Collins <> wrote:
    >
    > If an object is to be built by anything other than its constructor, it
    > can't have a const member.
    >


    I doubt you mean that this would be OK

    int
    Cd::Cd(Buffer* buf)
    {
    if (!buf->Give(const_cast<int*>(&az_), sizeof(int))) {
    buf->ews_.SetErrorWords(1, __FILE__, __LINE__);
    throw runtime_error("...");
    }
    }

    Probably you want to use the initializer list.

    > Why do you want one?
    >


    I don't have a specific application that needs this. I hope to
    improve the marshalling framework I'm working on so it can handle this
    possibility.

    Brian Wood
     
    , Feb 17, 2008
    #5
  6. Bo Persson Guest

    wrote:
    > On Feb 16, 11:41 pm, "Alf P. Steinbach" <> wrote:
    >> * :
    >>> [Is const_cast ok in marshalling code?]

    >>
    >> No.
    >>
    >> Cheers, & hth.,
    >>

    >
    > It helps, but why do you say that?
    >
    >


    Using const_cast on something that is actually declared const is not
    allowed. The compiler just might have stored it in read-only memory.

    You are allowed to remove const on things like a const reference
    parameter, *provided* that you know for a fact that the actual
    parameter is always non-const. If you make a mistake here, you enter
    Undefined Behavior land.


    Bo Persson
     
    Bo Persson, Feb 17, 2008
    #6
  7. Rolf Magnus Guest

    Bo Persson wrote:

    > wrote:
    >> On Feb 16, 11:41 pm, "Alf P. Steinbach" <> wrote:
    >>> * :
    >>>> [Is const_cast ok in marshalling code?]
    >>>
    >>> No.
    >>>
    >>> Cheers, & hth.,
    >>>

    >>
    >> It helps, but why do you say that?
    >>
    >>

    >
    > Using const_cast on something that is actually declared const is not
    > allowed. The compiler just might have stored it in read-only memory.


    However, it's quite unlikely that you find a compiler that stores one single
    member of an object in read-only memory.
     
    Rolf Magnus, Feb 17, 2008
    #7
  8. Guest

    On Feb 17, 7:58 am, "Bo Persson" <> wrote:
    >
    > Using const_cast on something that is actually declared const is not
    > allowed.


    OK. The compiler I'm using, gcc 4.0.3, warns about the above
    Receive function, but it builds it. I just tried compiling it
    as a ctor and in that case it gives a hard error.

    > The compiler just might have stored it in read-only memory.
    >
    > You are allowed to remove const on things like a const reference
    > parameter, *provided* that you know for a fact that the actual
    > parameter is always non-const. If you make a mistake here, you enter
    > Undefined Behavior land.
    >


    Any suggestions on how to do this without going into UB land?

    Brian Wood
     
    , Feb 17, 2008
    #8
  9. Bo Persson Guest

    Rolf Magnus wrote:
    > Bo Persson wrote:
    >
    >> wrote:
    >>> On Feb 16, 11:41 pm, "Alf P. Steinbach" <> wrote:
    >>>> * :
    >>>>> [Is const_cast ok in marshalling code?]
    >>>>
    >>>> No.
    >>>>
    >>>> Cheers, & hth.,
    >>>>
    >>>
    >>> It helps, but why do you say that?
    >>>
    >>>

    >>
    >> Using const_cast on something that is actually declared const is
    >> not allowed. The compiler just might have stored it in read-only
    >> memory.

    >
    > However, it's quite unlikely that you find a compiler that stores
    > one single member of an object in read-only memory.


    Yes, but do you want the code to be 100% portable, or is 98, 95, or
    53% good enough? It's your call.


    Bo Persson
     
    Bo Persson, Feb 17, 2008
    #9
  10. Bo Persson Guest

    wrote:
    > On Feb 17, 7:58 am, "Bo Persson" <> wrote:
    >>
    >> Using const_cast on something that is actually declared const is
    >> not allowed.

    >
    > OK. The compiler I'm using, gcc 4.0.3, warns about the above
    > Receive function, but it builds it. I just tried compiling it
    > as a ctor and in that case it gives a hard error.
    >
    >> The compiler just might have stored it in read-only memory.
    >>
    >> You are allowed to remove const on things like a const reference
    >> parameter, *provided* that you know for a fact that the actual
    >> parameter is always non-const. If you make a mistake here, you
    >> enter Undefined Behavior land.
    >>

    >
    > Any suggestions on how to do this without going into UB land?
    >


    There is no general solution. Either you know from the context that it
    will always work, or you will have to take some precautions. Exactly
    what you have to do I don't know - as usual, it depends.

    If nothing else works, you might have to use the baseball bat method.
    Visit all users of your code, and do some code reviews. If some of
    them don't meet the *well documented requirements*, hit them over the
    head with your baseball bat. Eventually, all the code will conform.


    Bo Persson
     
    Bo Persson, Feb 17, 2008
    #10
  11. Rolf Magnus Guest

    Bo Persson wrote:


    >>>> It helps, but why do you say that?
    >>>>
    >>>>
    >>>
    >>> Using const_cast on something that is actually declared const is
    >>> not allowed. The compiler just might have stored it in read-only
    >>> memory.

    >>
    >> However, it's quite unlikely that you find a compiler that stores
    >> one single member of an object in read-only memory.

    >
    > Yes, but do you want the code to be 100% portable, or is 98, 95, or
    > 53% good enough? It's your call.


    There is no 100% portable code beyond a trivial "hello world", and even that
    isn't really, since it's implementation defined what happens to data
    written to cout.
     
    Rolf Magnus, Feb 17, 2008
    #11
  12. Guest

    On Feb 17, 2:04 pm, "Bo Persson" <> wrote:

    > There is no general solution. Either you know from the context that it
    > will always work, or you will have to take some precautions. Exactly
    > what you have to do I don't know - as usual, it depends.
    >




    If instead of class Cd We use this:

    class Cd2 {
    int const az_;
    vector<string> co_;

    public:
    Cd2(int az, vector<string> co) : az_(az), co_(co) {}
    };


    The outline of the marshalling could be:
    marshall data into an int called arg1,
    marshall data into a vector<string> called arg2,
    build a Cd2 using arg1 and arg2.

    In other words, instead of the "stream constructor" having this form:
    Cd2(Buffer*);

    it could take each data member as input and use them in an
    initializer list. I think that would work no matter how the class
    members are declared. The constructor could be generated easily. One
    question with that, though is will it be inefficient because the
    vector of strings has to be copied? Perhaps the copy can be avoided,
    but if not the ctor might look like this:

    Cd2(int az, Buffer*) : az_(az)
    {
    use stream to assign data to co_
    }

    And I would document that const data members have to precede non-const
    data members if a type is going to be used in marshalling.


    > If nothing else works, you might have to use the baseball bat method.
    > Visit all users of your code, and do some code reviews. If some of
    > them don't meet the *well documented requirements*, hit them over the
    > head with your baseball bat. Eventually, all the code will conform.
    >


    Yeah, it can be a challenge.

    Brian Wood
     
    , Feb 18, 2008
    #12
  13. Guest

    On Feb 18, 12:40 pm, wrote:
    > If instead of class Cd We use this:
    >
    > class Cd2 {
    >   int const az_;
    >   vector<string> co_;
    >
    > public:
    >   Cd2(int az, vector<string> co) : az_(az), co_(co) {}
    >
    > };
    >
    > The outline of the marshalling could be:
    >  marshall datainto an int calledarg1,
    >  marshall datainto a vector<string> called arg2,
    >   build a Cd2 usingarg1and arg2.
    >
    > In other words, instead of the "stream constructor" having this form:
    > Cd2(Buffer*);
    >
    > it could take each data member as input and use them in an
    > initializer list.  I think that would work no matter how the class
    > members are declared.  The constructor could be generated easily.  One
    > question with that, though is will it be inefficient because the
    > vector of strings has to be copied?  Perhaps the copy can be avoided,
    > but if not the ctor might look like this:
    >
    > Cd2(int az, Buffer*) : az_(az)
    > {
    >   use stream to assign data to co_
    >
    > }
    >
    > And I would document that const data members have to precede non-const
    > data members if a type is going to be used in marshalling.
    >


    I compared the two approaches mentioned above in a simple test.
    The first version was typically 40-50% slower than the version that
    used an initializer list only to initialize const data
    members.

    Previously David Schwartz wrote about initializer lists,
    "Where you have a choice, and where things are otherwise equal, you
    should use an initializer list with 'complex' members. It avoids
    creating the member in its default state only to change it to the
    desired state later. For simple types, it would be unlikely to make
    any difference."

    Frequently that is sound advice, but in a marshalling context
    making a complex data member const to avoid creating the member
    in it's default state would probably be a blunder efficiency-wise.
    He did add the "where things are otherwise equal" clause so he
    may have anticipated some contexts where the advice wouldn't
    apply. I think const data members should be used sparingly in
    a marshalling context. If using a const data member improves the
    design it should be considered. If the member potentially has
    some heft to it data-wise, there is a trade-off between design sanity
    and efficiency to be weighed.

    I think the requirement to declare const data members before
    non-const data members would have to be made on behalf of any library/
    framework that intends to support efficient marshalling.

    Brian Wood
    Ebenezer Enterprises
     
    , Feb 20, 2008
    #13
    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. Kaspar Minosiants

    [help] const_cast

    Kaspar Minosiants, Jul 21, 2003, in forum: C++
    Replies:
    2
    Views:
    436
    John Harrison
    Jul 21, 2003
  2. drowned

    const_cast question

    drowned, Aug 4, 2003, in forum: C++
    Replies:
    3
    Views:
    493
    Josephine Schafer
    Aug 4, 2003
  3. R. Anbeeswaran

    const_cast<>

    R. Anbeeswaran, Nov 13, 2003, in forum: C++
    Replies:
    7
    Views:
    614
    Ekkehard Morgenstern
    Nov 14, 2003
  4. S.Senthilvel

    const_cast

    S.Senthilvel, Jan 6, 2004, in forum: C++
    Replies:
    4
    Views:
    2,049
    Andrey Tarasevich
    Jan 8, 2004
  5. d-42
    Replies:
    1
    Views:
    623
Loading...

Share This Page