STL迭代器和'const'

4

我在使用迭代器时遇到了一些隐式转换为const的问题。我不确定哪些代码是相关的(如果我知道,我可能就不会问这个问题了!),因此我将尽力说明我的问题。

typedef set<SmallObject> Container;              //not const

void LargeObject::someFunction() {               //not const
    Container::iterator it;                      //not const
    for (it = c.begin(); it != c.end(); ++it) {  //assume c is a "Container"
        (*it).smallObjectFunction();             //not a const function
    }
}

然而,我总是遇到以下错误:
error: passing 'const SmallObject' as 'this' argument of 'int SmallObject::smallObjectFunction()' discards qualifiers

然而,如果我将其转换为((SmallObject)(*it).smallObjectFunction();,那么我就可以摆脱错误信息。
我唯一能想到的是,某种方式上定义了
bool operator< (const SmallObject &a) const;

某种情况下,迭代器会返回const对象。这里需要帮助或解释吗?


请问您能否发布SmallObject的实现代码? - ULysses
3个回答

11

集合和映射会根据排序条件保持元素的顺序。为了使用户代码不破坏不变量,映射的key和集合中整个元素必须是恒定的。你的问题在于存储的元素不是SmallObject而是const SmallObject

如果没有限制,你可以:

int init[] = { 1, 2, 3, 4, 5 };
std::set<int> values( init, init+5 );
std::copy( values.begin(), values.end(), 
   std::ostream_iterator<int>(std::cout, " "));
   // 1 2 3 4 5
*(values.find(3)) = 5; // luckily this does not work!
std::copy( values.begin(), values.end(), 
   std::ostream_iterator<int>(std::cout, " "));
   // 1 2 5 4 5 -- not in order!!!

问题不仅在于现在集合元素没有顺序,而且根据树的构建方式,可能存在存在于集合中但无法找到的元素。


1
将 smallObjectFunction 函数设为 const(如果可以的话),这样就可以解决问题了。 - Patrick
我正在修改一些 smallObjectFunction 的对象。 我有哪些选项? 像我现在提到的那样进行强制转换吗? 从集合中删除,编辑,然后重新插入(很丑)? 还有别的方法吗? - sas4740
正确的做法是取出小对象进行编辑,然后再插入。否则,您可能会破坏 set 依赖的顺序和不变量,并且会得到意想不到的结果。如果更改不影响顺序,则可以使用带有任何键的映射并修改其值--即非常量。 - David Rodríguez - dribeas
在迭代过程中删除和插入对象会不会引起问题? - sas4740
在迭代时删除元素将会引起问题。处理它有不同的方式,通常需要复制迭代器,推进它,然后删除旧的副本。插入不会使迭代器无效,因此您可以随时插入,但是最好将修改后的元素保存在一个不同的容器中,并在完成迭代后将它们添加到集合中(以避免访问新元素)。如果您按照这个路径走,请注意可能在循环结束之前堆栈溢出并重新插入元素的异常。 - David Rodríguez - dribeas

3

您的代码并不愚蠢,并且如果符合STL实现的规范,可能会编译得很干净,这取决于STL实现所做的一些设计决策。 C++03标准没有指定set :: iteratorsreference typedef应该是什么(在我看来,它们应该是非常量引用)。因此,请继续您的工作,但插入一个const_cast

const_cast<SmallObject&>(*it).smallObjectFunction();

相比于擦除和重新插入,它更高效且更清晰。要深入讨论此问题,请查看Herb Sutter的《More Exceptional C++》中的第8项。

在这种情况下使用const_cast是完全安全的,而且这并不算是坏习惯,只需要确保您不更改确定排序的字段的值即可。如果类的接口使得难以验证您未更改顺序,则该接口可能设计不佳。


0

您的 c 容器中的对象是 const 类型,而 smallObjectFunction 尝试修改对象的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接