I have to refactor old code that looks like this (I am not a very proficient C++ coder)
std::set<SomeObject>::iterator it = setobject.begin();
do {
it->setProperty1ToNextValue();
it->getProperty2();
it->getProperty3();
it++
} while (it != setobject.end());
Basically I want to iterate through the elements of the set and get and set/update some of their properties.
I cant use the original set since I run in the problems described in this thread
the object has type qualifiers that are not compatible with the member function object type is const
I am thinking of replacing the set with a dequeue (it will involve some rewriting) since I will then be able to set and get properties on each element of the dequeue. Is this a good approach?
A std::set
works by keeping all the items in order according to the object's <
operator. The reason you cannot call non-const methods on your object is because there is risk that those methods will change the value returned by your objects <
operator, and therefore effectively "reorder" the set under the hood without the std::set
knowing.
While you haven't specified enough of what you are trying to do for us to provide the best answer, here is a couple ways to technically achieve calling some methods on your set. You can use const_cast
to call methods you are sure won't modify the key. Or you can put the items in a vector, call methods that might modify the "key", and then put them back in the original set.
// Example program
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
class SomeObject
{
std::string key;
int data;
public:
SomeObject( const std::string& key_, int data_ ) : key( key_ ), data( data_ )
{}
// For a item to be in a set, it must have a "<" operator that tells it how to order it
bool operator <( const SomeObject& rhs ) const
{
return key < rhs.key;
}
void setKey( const std::string& key_ )
{
key = key_;
}
void setData( int data_ )
{
data = data_;
}
};
int main()
{
std::set< SomeObject > setobject;
setobject.insert( SomeObject("c", 1 ) );
setobject.insert( SomeObject("a", 1 ) );
setobject.insert( SomeObject("b", 1 ) );
// internally, the set will keep everything in order "a", "b", "c"
// option 1 - use const_cast (risky!)
{
std::set< SomeObject >::iterator it = setobject.begin();
do {
// const_cast< SomeObject& >( *it ).setKey( "d" ); bad idea, now the set is jacked up because its not in the right order
const_cast< SomeObject& >( *it ).setData( 2 );
it++;
} while (it != setobject.end());
}
// option 2 - put the items in the vector, call the methods, then put them back in the original set
{
std::vector< SomeObject > tempVec( std::begin( setobject ), std::end( setobject ) );
std::vector< SomeObject >::iterator it = tempVec.begin();
do {
it->setKey( "d" );
it->setData( 2 );
it++;
} while (it != tempVec.end());
std::set< SomeObject > newSet( std::begin( tempVec ), std::end( tempVec ) );
std::swap( newSet, setobject ); // put the new items back in the original setobject
}
}