Unable to access non-const member functions of obj

2019-07-19 22:18发布

问题:

Message is a class I made. I have a set of them in the main function that I pass to messageTimeOut (and some other functions). In messageTimeOut using an itorator I am looping through them and accessing different member functions. However, I can only access const member functions of the Message pointed to by the iterator. If I try to access non const member functions I get the error:

“In function 'void messageTimeOut(threadParameters*)': main.cpp:74:33: error: passing 'const Message' as 'this' argument of 'void Message::setTimedOut(bool)' discards qualifiers [-fpermissive].”

It makes sense that I cannot access a non-const member function of a const Message object, but how do I go about making this a non const Message object so I can access non const member functions and change the Message? Thanks

Part of my code:

     [ . . . ]

void messageTimeOut( threadParameters* params )
{
     set<Message>::iterator it = params->messages->begin();
     [ . . . ]
    for ( ; it != params->messages->end(); ++it )
    {
        if ( (it->createdTime() + RESPONSE_WAIT) < GetTickCount() ) 
        {
            it->setTimedOut(true); // error 
        }
    }
    ReleaseMutex(sentQueueMutex);
}

     [ . . . ]

int main()
{
    threadParameters rmparameters;
    set<Message> sentMessages;
     [ . . . ]


    rmparameters.logFile = &logFile;
    rmparameters.socket = socketDesciptor;
    rmparameters.messages = &sentMessages;
      [ . . . ]

    messageTimeOut( rmparameters );
      [ . . . ]

    return 0;
}

回答1:

You can't.

Elements inside an std::set are always constant, because otherwise an user could modifiy the ordering in the set by modifying an element which belong to the set.

Notice that it doesn't matter that the function that you invoke doesn't change the ordering, since std::set has no way to check this.

A common way to fix this is to remove the element from the set, modify it, then reinsert it. Another way would be to use a map, even if this would probably force you to duplicate some data.



回答2:

You shouldn't be able to modify the contents of a std::set. Here's a reduced test case:

#include <set>
#include <iostream>

void print(int & data) {}

int main() {
    std::set<int> objects;

    objects.insert(3);
    print(*objects.find(3));
}

Clang would report the following errors:

blah.cc:14:2: error: no matching function for call to 'print'
        print(*objects.find(3));
        ^~~~~
blah.cc:4:6: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
void print(int & data) {
     ^

Therefore, it looks like using a set is not the correct decision to be made here.



回答3:

Objects in a set are const meaning that they are not mutable. Here are some options

1) Create copies of the messages in a new set
2) Remove the messages, mutate them, and put them back.
3) Remove the "timeout" field from the message.

Of these I prefer number 3. The fact that you are trying to mutate the messages is a "bad code smell". If you were to avoid all changing of data and instead create a new structure (for example a std::map) then you could reduce the amount of thread synchronization.