Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Question about overloaded operators

  1. #1
    Join Date
    Apr 2007
    Beans
    402
    Distro
    Ubuntu 10.04 Lucid Lynx

    Question about overloaded operators

    I'm working on a matrix class in C++ and have overloaded the parentheses () operator to provide me with element-level access to the matrix elements. I have two overloaded operators like this: one for read-only access to the elements, and one to modify.

    However I'm confused as to why the program is using the modifying version instead of the read-only version when I'm simply accessing the element.

    I've attached the source to a very-stripped down class along with a test program. I would expect the output to be

    Code:
    Modify
    Access
    Access
    but instead I get 3 "Modify"s. Perhaps someone can explain to me why this is, and how I can fix it?


    I should also note that I've tried the accessor function with a const in front of it, thusly:

    Code:
    const double operator()(int, int) const;
    but I still get the same results.
    Attached Files Attached Files
    Last edited by Volt9000; August 4th, 2009 at 03:28 AM.

  2. #2
    Join Date
    Aug 2006
    Location
    Madrid, Spain
    Beans
    299
    Distro
    Ubuntu 9.04 Jaunty Jackalope

    Re: Question about overloaded operators

    The const-version of your method will be used if invoked on a const-object. If the object is not const itself, or being accessed through a const-reference or pointer-to-const, the modifier version will be called even if the return value (which, for a modifier, should be double& and not double) is not actually modified.
    May the Source be with you.

  3. #3
    Join Date
    Jun 2007
    Location
    Maryland, US
    Beans
    6,288
    Distro
    Kubuntu

    Re: Question about overloaded operators

    I looked at the OP's code, and it appears that he has defined his overloaded operator()(int, int) correctly, although personally I would have used size_t in lieu of int, and I would have defined the parameters as const.

    BEGIN EDIT: I was wrong below..... IGNORE IGNORE IGNORE
    The only issue I found with the code is his access to the array of values; for example:
    Code:
    return _data[row * _cols + col];
    I may be wrong (once again I am posting early in the morning), but instead, shouldn't that be:
    Code:
    return _data[row * _rows + col];
    END EDIT
    ----------------------------------------------------------------------------
    Also, the OP may want to place some error-checking in his accessors so that illegal row/col values are screened out. Maybe use an assert() or throw an exception.

    One last thing... a destructor is needed to free the allocated memory. Alternatively, store the _data in an auto_ptr.
    Last edited by dwhitney67; August 4th, 2009 at 10:59 AM.

  4. #4
    Join Date
    Aug 2006
    Location
    Madrid, Spain
    Beans
    299
    Distro
    Ubuntu 9.04 Jaunty Jackalope

    Re: Question about overloaded operators

    Quote Originally Posted by dwhitney67 View Post
    Alternatively, store the _data in an auto_ptr.
    std::auto_ptr will use "delete _data;". The OP needs to use "delete[] _data;".

    Furthermore, instead of using memset, I would use one of the algorithms in the standard C++ library, such as fill_n. The line
    Code:
    memset(_data, 0, _rows * _cols * sizeof(double));
    would become
    Code:
    fill_n(_data, _rows * _cols, 0.0);
    May the Source be with you.

  5. #5
    Join Date
    Jun 2007
    Location
    Maryland, US
    Beans
    6,288
    Distro
    Kubuntu

    Re: Question about overloaded operators

    Quote Originally Posted by Habbit View Post
    std::auto_ptr will use "delete _data;". The OP needs to use "delete[] _data;".
    Yes, thanks for pointing that out; I discovered this issue moments after I posted my reply when I wrote a test program, and ran it with valgrind.

  6. #6
    Join Date
    Apr 2007
    Beans
    402
    Distro
    Ubuntu 10.04 Lucid Lynx

    Re: Question about overloaded operators

    Quote Originally Posted by Habbit View Post
    The const-version of your method will be used if invoked on a const-object. If the object is not const itself, or being accessed through a const-reference or pointer-to-const, the modifier version will be called even if the return value (which, for a modifier, should be double& and not double) is not actually modified.
    I see. So, then is there any way to "force" the program to invoke the const-method? Perhaps by redefining the signature? I only ask because what I would like to be able to do is to calculate things like the determinant and adjoint and store them, so if the user requests them again, as long as the matrix doesn't change, they won't have to be recalculated.

    And BTW, the modifier function's return value is indeed double&.

    Quote Originally Posted by dwhitney67 View Post
    I looked at the OP's code, and it appears that he has defined his overloaded operator()(int, int) correctly, although personally I would have used size_t in lieu of int, and I would have defined the parameters as const.
    Why size_t instead of int? Isn't size_t just a typedef'd unsigned int? If so, why not just use unsigned?

    Also, the OP may want to place some error-checking in his accessors so that illegal row/col values are screened out. Maybe use an assert() or throw an exception.
    Already have that in my class. The one I posted here was just a heavily-stripped version of the one I implemented for the sake of conciseness.

    One last thing... a destructor is needed to free the allocated memory. Alternatively, store the _data in an auto_ptr.
    Already have that too, see above.


    Quote Originally Posted by Habbit View Post
    Furthermore, instead of using memset, I would use one of the algorithms in the standard C++ library, such as fill_n. The line
    Code:
    memset(_data, 0, _rows * _cols * sizeof(double));
    would become
    Code:
    fill_n(_data, _rows * _cols, 0.0);
    I was originally going to use this, but I read somewhere than the fill_n function is inherently less efficient (slower?) than memset because of the way it's implemented.

    Is there any advantage to using one over the other? Is fill_n just more C++-ish?

  7. #7
    Join Date
    Jun 2007
    Location
    Maryland, US
    Beans
    6,288
    Distro
    Kubuntu

    Re: Question about overloaded operators

    Go with what works. I don't think you can get more efficient than memcpy(). I'm ol' school, so I have been using memcpy() for more than 20 years; maybe bytes have "shrunk" since then.

  8. #8
    Join Date
    Aug 2006
    Location
    Madrid, Spain
    Beans
    299
    Distro
    Ubuntu 9.04 Jaunty Jackalope

    Re: Question about overloaded operators

    Quote Originally Posted by Volt9000 View Post
    Is there any advantage to using one over the other? Is fill_n just more C++-ish?
    Using fill_n is safer and more consistent across all uses. While memset copies the same byte over all memory positions in the range, fill_n assigns every T/double slot in the range the value you passed.

    In this case you were lucky that the bit pattern for 0.0 was all zeros, or, in fact, some bit pattern with all bytes in each T/double identical to each other (by the way, didn't new[] default-initialize arrays, which for POD types means zero-initialization?). In other words, had you wanted to initialize the array to, say, 1.0, memset would have not cut it, while fill_n would have worked just the same, and without having to worry about sizeof(double) and IEEE-754 bit patterns.
    May the Source be with you.

  9. #9
    Join Date
    Apr 2007
    Beans
    402
    Distro
    Ubuntu 10.04 Lucid Lynx

    Re: Question about overloaded operators

    Alright.
    What about my original query?

    What I'd like to do is calculate certain computationally-heavy properties only once, and then access the saved values whenever the user requests them, and calculate only as necessary. The only time I would have to recalculate is when the user changes an element, hence the problem.

    Bottom line:
    I need to be able to distinguish between an element access just for reading, or an element access for changing.

    Any way to do this?

  10. #10
    Join Date
    Aug 2006
    Location
    Madrid, Spain
    Beans
    299
    Distro
    Ubuntu 9.04 Jaunty Jackalope

    Re: Question about overloaded operators

    That usually calls for the concept of a "property". One way to implement them is Java-like accesor methods: "const T& getX() const" and "void setX(const T&)" methods. When you set the property value in the setX method, you perform all required heavy computations, so that getX only performs fast reads.

    A more C++-ish, but more requiring of the programmer, would be to use some T_proxy class to implement the get/set semantics: you'd have an "operator T() const" which would do the "get", and implement an overloaded "Tproxy& operator=(const T&)" assignment operator to do the "set" and perform your computations. Your class would then expose these Tproxy instances instead of instances of T itself.

    This last approach certainly looks _way_ cleaner on user code, but is more of a pain to the implementer: you have to weigh the pros and cons.
    May the Source be with you.

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •