私はJavaコードの大部分をC++に移植してきましたが、LinkedHashSetのようなものを実装する必要がありました。Boostのマルチインデックスコンテナを使用して、LinkedHashSet/Mapの妥当な複製を作成しました。
コードを移植しているときに、multi_indexを使用していくつかの興味深いものに遭遇します。これは、含まれているオブジェクトが変更可能ではないためです(クラスの特定のフィールドを変更可能としてマークしない限り)。ただし、含まれているクラスのいくつかの可変メンバーからキーが計算される場合、物事は興味深いものになる可能性があります。
いくつかのことを明確にするために、Javaで簡単な例を書いてLinkedHashSetの動作を確認すると思いました。結果は私には少し驚くべきものです。含まれているオブジェクトが変更されてもインデックスが再生成されないという点で、Boostのマルチインデックスコンテナのように動作するようです(ご想像のとおり)。ただし、コンパイラはまったく文句を言いません---足元で自分を撃つのは非常に簡単なようです(私が移植しているコードは、それがまだどのように機能するかを知っている前述の罪を犯しているようです)。
これは、Javaにconst_iteratorsがないことの単なる制限ですか、それとも私は特に愚かでトリッキーなことをすることができましたか?
簡単な例を次に示します。
class StringContainer
{
public String s;
public StringContainer(String s)
{
this.s = s;
}
public boolean equals(Object t1)
{
StringContainer other = (StringContainer) t1;
return this.s == other.s;
}
public int hashCode()
{
int val = 8;
for (int i = 0; i < s.length(); i++)
val += s.charAt(i);
return val;
}
public String toString()
{
return s;
}
}
class test
{
public static void main(String[] args)
{
Set<StringContainer> set = new LinkedHashSet();
set.add(new StringContainer("Foo"));
set.add(new StringContainer("Bar"));
set.add(new StringContainer("Baz"));
set.add(new StringContainer("Qux"));
Iterator<StringContainer> it = set.iterator();
while (it.hasNext())
{
StringContainer s = it.next();
if (s.s == "Baz")
s.s = "Baz2";
System.out.println(s);
}
System.out.println("\nRe-iterate:\n");
it = set.iterator();
while (it.hasNext())
{
StringContainer s = it.next();
System.out.println(s);
}
System.out.println();
if (set.contains(new StringContainer("Foo")))
System.out.println("Contains Foo");
if (set.contains(new StringContainer("Baz")))
System.out.println("Contains Baz");
else
System.out.println("Does not contain Baz");
if (set.contains(new StringContainer("Baz2")))
System.out.println("Contains Baz2");
else
System.out.println("Does not contain Baz2");
}
}
次のように出力されます。
Foo
Bar
Baz2
Qux
Re-iterate:
Foo
Bar
Baz2
Qux
Contains Foo
Does not contain Baz
Does not contain Baz2
興味深いことに、それはバズが変わったことを知っています。ただし、それでもBaz2は見つかりません。
明らかにこれは不自然ですが、私が見ている非常にもっともらしいコードは(複数の間接的な方法で)この問題を引き起こしているようです。Boost Multi Indexでは、少なくともこれを引き起こすにはイテレータをconst-castする必要があります!