在 C++ 中替换集合的最佳方法
Best way to replace a set in C++
我必须重构看起来像这样的旧代码(我不是一个非常熟练的 C++ 编码器)
std::set<SomeObject>::iterator it = setobject.begin();
do {
it->setProperty1ToNextValue();
it->getProperty2();
it->getProperty3();
it++
} while (it != setobject.end());
基本上我想遍历集合的元素并获取和 set/update 它们的一些属性。
我无法使用原始设置,因为我 运行 在此线程中描述的问题
我正在考虑用出列替换集合(这将涉及一些重写),因为这样我就可以设置和获取出列的每个元素的属性。这是一个好方法吗?
A std::set
通过根据对象的 <
运算符保持所有项目的顺序来工作。你不能在你的对象上调用 non-const 方法的原因是因为这些方法有可能改变你的对象返回的值 <
运算符,因此有效地 "reorder" 引擎盖下的集合在 std::set
不知情的情况下。
虽然您没有详细说明您要尝试为我们提供最佳答案,但这里有几种方法可以从技术上实现调用您的集合上的某些方法。您可以使用 const_cast
来调用您确定不会修改密钥的方法。或者,您可以将项目放入向量中,调用可能修改 "key" 的方法,然后将它们放回原始集中。
// 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
}
}
我必须重构看起来像这样的旧代码(我不是一个非常熟练的 C++ 编码器)
std::set<SomeObject>::iterator it = setobject.begin();
do {
it->setProperty1ToNextValue();
it->getProperty2();
it->getProperty3();
it++
} while (it != setobject.end());
基本上我想遍历集合的元素并获取和 set/update 它们的一些属性。
我无法使用原始设置,因为我 运行 在此线程中描述的问题
我正在考虑用出列替换集合(这将涉及一些重写),因为这样我就可以设置和获取出列的每个元素的属性。这是一个好方法吗?
A std::set
通过根据对象的 <
运算符保持所有项目的顺序来工作。你不能在你的对象上调用 non-const 方法的原因是因为这些方法有可能改变你的对象返回的值 <
运算符,因此有效地 "reorder" 引擎盖下的集合在 std::set
不知情的情况下。
虽然您没有详细说明您要尝试为我们提供最佳答案,但这里有几种方法可以从技术上实现调用您的集合上的某些方法。您可以使用 const_cast
来调用您确定不会修改密钥的方法。或者,您可以将项目放入向量中,调用可能修改 "key" 的方法,然后将它们放回原始集中。
// 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
}
}