我用自定义迭代器编写了一个自定义容器。由于容器的特定功能,迭代器必须被懒惰地评估。对于这个问题的缘故代码的相关部分是迭代的对其操作它以这种方式实现编译器优化打破了懒惰的迭代器
template<typename T>
struct Container
{
vector<T> m_Inner;
// This should calculate the appropriate value.
// In this example is taken from a vec but in
//the real use-case is calculated on request
T Value(int N)
{ m_Inner.at(N); }
}
template<typename T>
struct Lazy_Iterator
{
mutable pair<int, T> m_Current;
int Index
Container<T>* C
Lazy_Iterator(const Container& Cont, int N):
m_Current{Index, T{}}, Index{N}, C{&Cont}
{ }
pair<int, T>&
operator*() const // __attribute__((noinline)) (this cures the symptom)
{
m_Current.first = Index; /// Optimized out
m_Current.second = C->Value(Index); /// Optimized out
return m_Current;
}
}
因为迭代器本身是一个模板,它的功能可以自由通过编译器内联。
当我没有优化编译代码时,返回的值按预期更新。当我使用发布编译器优化(在GCC 4.9中为-O2)时,在某些情况下,即使m_Current成员标记为可变,编译器也会优化我标记为优化出的的行。因此返回值与迭代器应该指向的值不匹配。
这是预期的行为?你知道任何可移植的方式来指定该函数的内容应该被评估,即使它被标记为const吗?
我希望这个问题足够详尽,有用。如果在这种情况下更多细节可能会有所帮助,请咨询。
编辑:
要回答一个评论,这是从一个小的测试程序采取了潜在的使用:
Container<double> myC;
Lazy_Iterator<double> It{myC, 0}
cout << "Creation: " << it->first << " , " << it->second << endl;
auto it2 = it;
cout << "Copy: "<< it2->first << " , " << it2->second << endl;
cout << "Pre-increment: " << (it++)->first << " , " << it->second << endl;
cout << "Post-increment: " << (++it)->first << " , " << it->second << endl;
cout << "Pre-decrement: " << (it--)->first << " , " << it->second << endl;
cout << "Post-decrement: " << (--it)->first << " , " << it->second << endl;
cout << "Iterator addition: " << (it+2)->first << " , " << (it+2)->second << endl;
cout << "Iterator subtraction: "<< (it-2)->first << " , " << (it-2)->second << endl;
reverse_iterator<Lazy_Iterator> rit{it};
cout << "Reverse Iterator: " << rit->first << " , " << rit->second << endl;
auto rit2 = rit;
cout << "Reverse Iterator copy: " << rit2->first << " , " << rit2->second << endl;
cout << "Rev Pre-increment: " << (rit++)->first << " , " << rit->second << endl;
cout << "Rev Post-increment: " << (++rit)->first << " , " << rit->second << endl;
cout << "Rev Pre-decrement: " << (rit--)->first << " , " << rit->second << endl;
cout << "Rev Post-decrement: " << (--rit)->first << " , " << rit->second << endl;
cout << "Rev Iterator addition: " << (rit+2)->first << " , " << (rit+2)->second << endl;
cout << "Rev Iterator subtraction: "<< (rit-2)->first << " , " << (rit-2)->second << endl;
测试结果是否如预期般对所有测试除了最后两行
开启优化时,测试的最后两行发生故障。
该系统实际上运行良好,并不比其他迭代器更危险。当然,如果容器在他的鼻子下被删除,它可能会失败,并且通过复制使用返回的值可能会更安全,而不仅仅是保留参考,但这是脱离主题
这是一个很好的问题,但是您认为您可以编辑代码片段来获取错别字吗? – Bathsheba
你指的是哪种拼写错误?我改变了我忘记替换的typedefs的类型。如果有更多,请让我知道 – Triskeldeian
你能提供[mcve]吗?目前在问题中的代码看起来是正确的。 – Angew