Thread: returning reference

  1. #16
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    std::map<>:: operator[] is non-const, so you can't call it from inside a const function. Use find() instead.

  2. #17
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Note that you will have problems if the key does not exist.

    One option is to make the map mutable, which would allow you to leave the other code the way it is. This only makes sense if you want to allow users to specify an invalid key and you'd rather return a new default constructed someobject than throw any kind of error. Making the map mutable unfortunately no longer allows the compiler to error out when you accidentally modify it, but if the behavior I described is what you want then that might be the best solution.

    You could also just throw an exception on an invalid key or document the function to say that invalid keys cause undefined behavior. Those options make more sense if you don't expect the user to ever specify an invalid key.

  3. #18
    Registered User
    Join Date
    May 2006
    Posts
    630
    Someone mentioned once on this forum that is totally okay to have that kind of functions and just require from the user to check is_key_in_map() before calling the get_object() function so I thought it would be okay to make it this way and always do the checking first.

  4. #19
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by l2u View Post
    Someone mentioned once on this forum that is totally okay to have that kind of functions and just require from the user to check is_key_in_map() before calling the get_object() function so I thought it would be okay to make it this way and always do the checking first.
    It's not okay because the operator[] itself isn't const. Even if you verify the key is in the map, the non-constness doesn't magically go away. Again... Use find()

  5. #20
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Someone mentioned once on this forum that is totally okay to have that kind of functions and
    >> just require from the user to check is_key_in_map() before calling the get_object() function so
    >> I thought it would be okay to make it this way and always do the checking first.

    Sure it's ok. As I said, in that case you could just throw an exception on an invalid key or document the function to say that invalid keys cause undefined behavior. You still should make a decision on how to handle when find() doesn't find the key. If you just dereference the result of find, then make sure you document that invalid keys are not allowed and undefined behavior will result.

    Or you can define the behavior by checking the result of find() against end() and throwing an exception, although it sounds like you don't want to add that complexity. If not, then add an assert that verifies the result of find is not end().

    BTW, I'm assuming you understood that if you don't make the map mutable (which you shouldn't because it doesn't fit your use case) then you have to use find().

  6. #21
    Registered User
    Join Date
    May 2006
    Posts
    630
    I dont want to allow users to specify an invalid key (this shouldnt happen).

    So the only way is to go with find() (as I understood).. Do you think it would be better in this case to check is the key exists and throw exception if it doesnt?

    I think this is something similar to:

    Code:
    someclass {
    public:
      std::string get_name(int n) { return m_names[n]; }
    private:
      std::vector<std::string> m_names;
    };
    Should I check with all that kind of functions if the name exists (and throw exception in other case) although users shouldnt be allowed do get() before doing the check first.

  7. #22
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You should check before the user does a get, I think.
    Also note that operator [] inserts an element if it doesn't exist, so if the user did specify an invalid key, it would insert a new key instead of complaining. So yes, I think find and throwing an error might be a good approach.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #23
    Registered User
    Join Date
    May 2006
    Posts
    630
    Quote Originally Posted by Elysia View Post
    You should check before the user does a get, I think.
    Also note that operator [] inserts an element if it doesn't exist, so if the user did specify an invalid key, it would insert a new key instead of complaining. So yes, I think find and throwing an error might be a good approach.
    Im not sure this would add an element if it doesnt exist:
    Code:
    const someobject &get_object(std::string str) const { return m_map[str]; }

    So before return I should make checking anyway and throw an exception?

  9. #24
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, it would.
    std::map always inserts an object if it does not exist, when using the index operator.
    If you only want to find and return an object, use find.
    Find returns an iterator which you have to check against yourmap.end() (if it's equal, then the element doesn't exist) because the standard library was so poorly designed.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #25
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    Find returns an iterator which you have to check against yourmap.end() (if it's equal, then the element doesn't exist) because the standard library was so poorly designed.
    I think this is one area where the standard library was well designed instead.

    EDIT:
    On second thought, if you are referring to the need to compare with map.end(), then perhaps that could have been done differently, e.g., to return a singular iterator that evaluates to false, whereas all non-end iterators evaluate to true. On the other hand, the safe bool idiom was not known at the time these class templates were designed, conversion to void* had its problems, and comparison with end() is consistent with the usual range comparison, so it is still a stretch to say that "the standard library was so poorly designed" in this area.
    Last edited by laserlight; 04-16-2008 at 07:00 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #26
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Should I check with all that kind of functions if the name exists

    Again, that's up to you. If you know the calling functions will be smart and not use an invalid key, then just assert in debug mode if find() returns end(). In Release mode you would just use the result of find directly and if the user uses a key that doesn't exist then it is their fault.

    Throwing an exception is a good choice, but it has performance implications. If you don't have other checks in place in your code then using an exception is a good idea.

  12. #27
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by laserlight View Post
    I think this is one area where the standard library was well designed instead.

    EDIT:
    On second thought, if you are referring to the need to compare with map.end(), then perhaps that could have been done differently, e.g., to return a singular iterator that evaluates to false, whereas all non-end iterators evaluate to true. On the other hand, the safe bool idiom was not known at the time these class templates were designed, conversion to void* had its problems, and comparison with end() is consistent with the usual range comparison, so it is still a stretch to say that "the standard library was so poorly designed" in this area.
    Well, I like to vent my frustration with how it was designed sometimes, so yes...
    Comparing the iterator to true or false would be a big improvement, but perhaps another solution might be like MFC does it. Take a reference and return true/false.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #28
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Elysia View Post
    ... because the standard library was so poorly designed.
    Next thing you'll be telling a rocket scientist how to get a space shuttle to the moon.
    In short, you're not qualified to make such a judgement. nor am I, you could say

    I see you've learnt the CRTP.
    The code you posted beginning with the following, is an over-engineered solution looking for a problem:
    Code:
    template<typename Type, typename Class> class CUtilityMember
    ...
    Last edited by iMalc; 04-17-2008 at 03:00 AM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  14. #29
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I knew I would get blamed for that
    But that's OK, we all have our opinions.
    But let's just say it isn't a judgement, it's an opinion. A judgement it is when everyone agrees.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #30
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Quote Originally Posted by l2u View Post
    Hello

    If I have the following data structure:

    Code:
    class options {
    public:
    	void set_value(int v) { m_value = v; }
    	int get_value() { return m_value; }
    private:
    	int m_value;
    };
    
    class someclass {
    public:
    	options &get_options() { return m_options; }
    private:
    	options m_options;
    };
    What is the right way to return m_options by reference?
    Don't do it. Why do you want to return a reference to your private data? If your object is really a POD, make it a struct.

    I'd also revisit the design. If you have a bunch of classes passing around and operating on a data struct, you may want encapsulate that data in an object with real behavior.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM