const_cast<...>(this)

Discussion in 'C++' started by Squeamizh, Oct 15, 2006.

  1. Squeamizh

    Squeamizh Guest

    class my_class {
    public:
    my_class() : value(0) { }
    int& get_value() { return value; }

    const int& get_value() const {
    my_class& c = const_cast<my_class&>(*this);
    return c.get_value();
    }

    private:
    int value;
    };

    int main() {
    const my_class c;
    return c.get_value();
    }

    Does the above cause undefined behavior?

    Thanks
     
    Squeamizh, Oct 15, 2006
    #1
    1. Advertising

  2. * Squeamizh:
    > class my_class {
    > public:
    > my_class() : value(0) { }
    > int& get_value() { return value; }
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > private:
    > int value;
    > };
    >
    > int main() {
    > const my_class c;
    > return c.get_value();
    > }
    >
    > Does the above cause undefined behavior?


    No, but (1) it would if you tried to modify the object, because it's
    originally declared 'const', and (2) instead of the monstrosity above,
    where you expose a data member completely via absurd code, you could and
    probably should simply do

    struct MyClass
    {
    int value;
    MyClass(): value( 0 ) {}
    };

    If you absolutely want to use a Java-like "getter" (it has a purpose in
    Java, namely to support component usage via instrospection) then I
    suggest you change the name 'get_value' to simply 'value'.

    You don't write

    get_sin(0.5)*get_cos(0.5)

    do you?

    --
    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, Oct 15, 2006
    #2
    1. Advertising

  3. Squeamizh

    Squeamizh Guest

    Alf P. Steinbach wrote:
    > > [const_cast<...>(this)]
    > > Does the above cause undefined behavior?

    >
    > No, but (1) it would if you tried to modify the object, because it's
    > originally declared 'const', and (2) instead of the monstrosity above,
    > where you expose a data member completely via absurd code, you could and
    > probably should simply do
    >
    > [struct]


    I agree. The code I posted was simplified in order to clearly express
    the root of my concern. Since you brought it up, though, I'd be
    grateful to hear if you think I am using the wrong solution for my
    problem. I originally had a class declaration that looks like this:

    class my_class {
    public:
    virtual int& get_value() = 0;
    virtual const int& get_value() const = 0;
    };

    my_class does not actually contain an "int value" (hence the pure
    virtual getter) because I would like to have a descendant of my_class
    ("class outer") that contains another descendant of my_class ("class
    inner"). inner contains the actual "int value", and outer just
    delegates the above two functions to inner. However, I don't want
    outer to have to override both a non-const version of get_value and a
    const version of get_value. I would like to avoid the tediousness of
    overriding twice as many getters in all these classes.

    This may still seem absurd, but it is still a bit simplified. There
    are actually eight or so getters like the above, and several different
    "outer" and "inner" classes that all inherit my_class.

    > If you absolutely want to use a Java-like "getter" (it has a purpose in
    > Java, namely to support component usage via instrospection) then I
    > suggest you change the name 'get_value' to simply 'value'.
    >
    > You don't write
    >
    > get_sin(0.5)*get_cos(0.5)
    >
    > do you?


    Again, I agree. I often have difficulty reading the snippets that
    others post, and I thought the addition of "get" would make it easier
    to read my example.
     
    Squeamizh, Oct 15, 2006
    #3
  4. Squeamizh

    Kai-Uwe Bux Guest

    Alf P. Steinbach wrote:

    > * Squeamizh:
    >> class my_class {
    >> public:
    >> my_class() : value(0) { }
    >> int& get_value() { return value; }
    >>
    >> const int& get_value() const {
    >> my_class& c = const_cast<my_class&>(*this);
    >> return c.get_value();
    >> }
    >>
    >> private:
    >> int value;
    >> };
    >>
    >> int main() {
    >> const my_class c;
    >> return c.get_value();
    >> }
    >>
    >> Does the above cause undefined behavior?

    >
    > No, but (1) it would if you tried to modify the object, because it's
    > originally declared 'const',


    The compiler would bark at the attempt:

    const int& get_value() const {
    my_class& c = const_cast<my_class&>(*this);
    return c.get_value();
    }

    As you can see, the const version of get_value returns a const int &.

    > and (2) instead of the monstrosity above,
    > where you expose a data member completely via absurd code, you could and
    > probably should simply do
    >
    > struct MyClass
    > {
    > int value;
    > MyClass(): value( 0 ) {}
    > };
    >
    > If you absolutely want to use a Java-like "getter" (it has a purpose in
    > Java, namely to support component usage via instrospection) then I
    > suggest you change the name 'get_value' to simply 'value'.
    >
    > You don't write
    >
    > get_sin(0.5)*get_cos(0.5)
    >
    > do you?
    >


    I think the OP is not really interested in the particular example. Instead,
    I think the code is an attempt at avoiding code-duplication. A more natural
    example would be a smart-pointer where you have

    T* operator* ( void );

    and

    T const * operator* ( void ) const;

    and both functions usually have the same body. I am not sure what to think
    of the const_cast<> approach, though. It seems that unless it is an
    established idiom within your peer group, you would have to put in a
    comment saying that you checked the standard and that this use of
    const_cast<> is benign---hardly better than just duplicating the code of a
    one-line function body.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 15, 2006
    #4
  5. * Squeamizh:
    > Alf P. Steinbach wrote:
    >>> [const_cast<...>(this)]
    >>> Does the above cause undefined behavior?

    >> No, but (1) it would if you tried to modify the object, because it's
    >> originally declared 'const', and (2) instead of the monstrosity above,
    >> where you expose a data member completely via absurd code, you could and
    >> probably should simply do
    >>
    >> [struct]

    >
    > I agree. The code I posted was simplified in order to clearly express
    > the root of my concern. Since you brought it up, though, I'd be
    > grateful to hear if you think I am using the wrong solution for my
    > problem. I originally had a class declaration that looks like this:
    >
    > class my_class {
    > public:
    > virtual int& get_value() = 0;
    > virtual const int& get_value() const = 0;
    > };
    >
    > my_class does not actually contain an "int value" (hence the pure
    > virtual getter) because I would like to have a descendant of my_class
    > ("class outer") that contains another descendant of my_class ("class
    > inner"). inner contains the actual "int value", and outer just
    > delegates the above two functions to inner.


    Ah, design issue. First off, this is a separate issue from the const
    overloading issue. This issue is about one class, here 'my_class',
    requiring that some other class, here 'inner', provides a member of a
    given type (because of the references).

    I.e., that one class dictates the /implementation/ of another class.

    That's generally UnGood.

    At the very least, try to separate implementation from interface, by

    class MyClass
    {
    public:
    virtual int value() const = 0;
    virtual void setValue( int v ) = 0;
    };

    But note that this interface is essentially an interface to a /global
    variable/ -- where I'm using the term "global" very loosely, but the
    point is that the value can be modified from anywhere, and in the end
    someone will have to resort to painful debugging and searching of tons
    of code to establish where the heck the final useful value comes from,
    or where the code is that puts in a very much less than useful value...

    The problem is the public setter function.

    The solution depends strongly on what the actual design is all about,
    but generally, most designs where the client code changes values (this
    makes it all but impossible to maintain any class invariants) can be
    recast as more reasonable designs where the client code just states the
    effects or results wanted -- operations, not raw data.


    [moved this paragraph up here from further down in the text]
    > This may still seem absurd, but it is still a bit simplified. There
    > are actually eight or so getters like the above, and several different
    > "outer" and "inner" classes that all inherit my_class.


    Ouch. Those eight or so values seem to be strongly related, and if they
    aren't, they should be, to appear in the same interface. Why not pack
    them in a class and provide just /one/ set-and-get pair, or better yet,
    as mentioned above, a single getter function 'T const& value() const',
    or even better better yet, as mentioned above, operations, not raw data?

    OK, I know one reason: an unreasonable psychotic project lead who
    absolutely don't want any such "fancy" stuff, it /must/ be spaghetti,
    visually identical in texture (yes) to the rest of the code.

    But apart from that?


    > However, I don't want
    > outer to have to override both a non-const version of get_value and a
    > const version of get_value. I would like to avoid the tediousness of
    > overriding twice as many getters in all these classes.


    Note: at least for primitive types such as 'int' those aren't really
    getters, they're setters camouflaged as getters, because they return
    references.

    But when you have a getter where the constness of the result should
    depend on the constness of *this, and the logic of that getter is
    complex, deferring to a common implementation and using const_cast is
    all right (the common implementation can be templatized in order to
    avoid the cast, but that's very seldom worth the coding investment).


    --
    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, Oct 15, 2006
    #5
  6. * Kai-Uwe Bux:
    > Alf P. Steinbach wrote:
    >
    >> * Squeamizh:
    >>> class my_class {
    >>> public:
    >>> my_class() : value(0) { }
    >>> int& get_value() { return value; }
    >>>
    >>> const int& get_value() const {
    >>> my_class& c = const_cast<my_class&>(*this);
    >>> return c.get_value();
    >>> }
    >>>
    >>> private:
    >>> int value;
    >>> };
    >>>
    >>> int main() {
    >>> const my_class c;
    >>> return c.get_value();
    >>> }
    >>>
    >>> Does the above cause undefined behavior?

    >> No, but (1) it would if you tried to modify the object, because it's
    >> originally declared 'const',

    >
    > The compiler would bark at the attempt:
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > As you can see, the const version of get_value returns a const int &.


    Consider e.g.

    int const& value() const
    {
    MyClass& c = const_cast<my_class&>(*this);
    int& refValue = c.value();

    if( refValue == 0 ) { refValue = 666; }
    return refValue;
    }

    Another problem, that I've mentioned elsethread, is that 'int const&' as
    opposed to just 'int' forces a given implementation, /and/ may be less
    efficient...

    And a third problem, also mentioned elsethread, is that the non-const
    "getter" function is in reality a setter function.

    Rest snipped - agreed.

    Cheers,

    - 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, Oct 15, 2006
    #6
  7. Squeamizh

    S S Guest

    Squeamizh wrote:
    > class my_class {
    > public:
    > my_class() : value(0) { }
    > int& get_value() { return value; }
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > private:
    > int value;
    > };
    >
    > int main() {
    > const my_class c;
    > return c.get_value();
    > }
    >
    > Does the above cause undefined behavior?
    >

    You are not returning const int& as you have modified it. That is
    wrong.
    The purpose of calling const function is defied here. If you are
    calling const function, you must have const obj in first place and then
    inside it you are not supposed to modify it. The better way to do it
    reverse. Call const version of function from non const one.

    int& get_value()
    {
    return const_cast<int&>(static_cast<const myclass&)(*this));
    //Here I am casting away constness in return type and adding const to
    *this's type. This will call non const version of function.
    }
    This will aviod code duplication as well as work fine.

    > Thanks
     
    S S, Oct 15, 2006
    #7
  8. Squeamizh

    S S Guest

    S S wrote:
    > Squeamizh wrote:
    > > class my_class {
    > > public:
    > > my_class() : value(0) { }
    > > int& get_value() { return value; }
    > >
    > > const int& get_value() const {
    > > my_class& c = const_cast<my_class&>(*this);
    > > return c.get_value();
    > > }
    > >
    > > private:
    > > int value;
    > > };
    > >
    > > int main() {
    > > const my_class c;
    > > return c.get_value();
    > > }
    > >
    > > Does the above cause undefined behavior?
    > >

    > You are not returning const int& as you have modified it. That is
    > wrong.
    > The purpose of calling const function is defied here. If you are
    > calling const function, you must have const obj in first place and then
    > inside it you are not supposed to modify it. The better way to do it
    > reverse. Call const version of function from non const one.
    >
    > int& get_value()
    > {


    a correction

    > return const_cast<int&>(static_cast<const myclass&)(*this).get_value());
    > //Here I am casting away constness in return type and adding const to
    > *this's type. This will call non const version of function.
    > }
    > This will aviod code duplication as well as work fine.
    >
    > > Thanks
     
    S S, Oct 15, 2006
    #8
  9. Squeamizh

    Guest

    Squeamizh wrote:
    > class my_class {
    > public:
    > my_class() : value(0) { }
    > int& get_value() { return value; }
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > private:
    > int value;
    > };
    >
    > int main() {
    > const my_class c;
    > return c.get_value();
    > }
    >
    > Does the above cause undefined behavior?


    Not yet, but you probably want to read up on mutable.

    HTH,
    Michiel Salters
     
    , Oct 17, 2006
    #9
  10. Squeamizh

    Noah Roberts Guest

    Squeamizh wrote:
    > class my_class {
    > public:
    > my_class() : value(0) { }
    > int& get_value() { return value; }
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > private:
    > int value;
    > };


    It makes more sense to go the other way; make the non-const version
    call the const version. Of course, the assumption is that you are
    returning the same value but possibly doing something on the side when
    not const. Chances are your in poor design mode but whatever...make
    the non-const version call the const version. Then you can't run into
    UB.

    > Does the above cause undefined behavior?


    No, but your getting close to causing UB. The above code also has
    pointless functions...you don't need the non-const version at all.
     
    Noah Roberts, Oct 17, 2006
    #10
  11. Squeamizh

    Earl Purple Guest

    Squeamizh wrote:
    > class my_class {
    > public:
    > my_class() : value(0) { }
    > int& get_value() { return value; }
    >
    > const int& get_value() const {
    > my_class& c = const_cast<my_class&>(*this);
    > return c.get_value();
    > }
    >
    > private:
    > int value;
    > };
    >
    > int main() {
    > const my_class c;
    > return c.get_value();
    > }


    A better example:

    template < typename T >
    class Matrix
    {
    std::vector< T > vec;
    size_t numRows;
    size_t numCols;

    public:
    Matrix( size_t r, size_t c, T t = T() )
    : vec( r * c, t ),
    numRows( r ),
    numCols ( c )
    {
    }

    T& operator() ( size_t row, size_t col )
    {
    return vec[ row * numCols + col ];
    }

    const T& operator() ( size_t row, size_t col ) const
    {
    return vec[ row * numCols + col ];
    }
    };

    Very simple matrix template. Should your two operator() calls have the
    same body? What if you later want to introduce bounds checking and
    throw a range_error if the indices are out of bounds. We could add a
    validate_bounds() command but we'd still have to call it from both
    operator() overloads.

    So the question is (probably the OPs question), should we get one
    overload to call the other (or call a common function) using a
    const_cast to override the constness. If so, how?

    Is there a general way to resolve the problem whilst maintaining strict
    constness, i.e. a way that would work without any const-casts and would
    break (at compile time) if the const version really did modify anything
    (other than a mutable).
     
    Earl Purple, Oct 17, 2006
    #11
  12. Squeamizh

    Squeamizh Guest

    Noah Roberts wrote:
    > It makes more sense to go the other way; make the non-const version
    > call the const version. Of course, the assumption is that you are
    > returning the same value but possibly doing something on the side when
    > not const. Chances are your in poor design mode but whatever...make
    > the non-const version call the const version. Then you can't run into
    > UB.


    How does that make more sense? Wouldn't that result in undefined
    behavior when the client then modifies the returned int?

    > > Does the above cause undefined behavior?

    >
    > No, but your getting close to causing UB. The above code also has
    > pointless functions...you don't need the non-const version at all.


    Heh... I don't need the non-const version because it is never called it
    in the snippet I provided. The implication is that I need both the
    non-const and the const versions.
     
    Squeamizh, Oct 17, 2006
    #12
    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:
    429
    John Harrison
    Jul 21, 2003
  2. drowned

    const_cast question

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

    const_cast<>

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

    const_cast

    S.Senthilvel, Jan 6, 2004, in forum: C++
    Replies:
    4
    Views:
    2,044
    Andrey Tarasevich
    Jan 8, 2004
  5. Gajanan Bhat

    const_cast question

    Gajanan Bhat, May 4, 2004, in forum: C++
    Replies:
    9
    Views:
    554
    Bill Seurer
    May 5, 2004
Loading...

Share This Page