Fixed accessing members of the dereferenced value after iterator post-increment.

The recent commit 5777e9944b broke code such as
(*it++).foo(), where the result of dereferencing would be convertible to
the value type but did not provide the members of the value type. To mitigate
this, return a reference to the value instead of a proxy object. This will only
work for non-writable iterators (and it didn't work for writable iterators
before either) because in that case a proxy is needed to be able to intercept
operator=.

Also fix a similar issue with (it++)->foo() by adding operator-> overloads
to the post-increment result proxies.

Added tests for the fixes.
This commit is contained in:
Andrey Semashev
2022-11-18 00:39:26 +03:00
parent 0a95636faf
commit 7c9b4296a1
2 changed files with 66 additions and 44 deletions
+24 -39
View File
@@ -150,54 +150,25 @@ namespace iterators {
// value must be read and stored away before the increment occurs
// so that *a++ yields the originally referenced element and not
// the next one.
template <class Value>
class postfix_increment_dereference_proxy
template <class Iterator>
class postfix_increment_proxy
{
typedef Value value_type;
public:
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template<typename OtherValue>
explicit postfix_increment_dereference_proxy(OtherValue&& x)
: stored_value(static_cast< OtherValue&& >(x))
{}
#else
explicit postfix_increment_dereference_proxy(value_type const& x)
: stored_value(x)
{}
typedef typename iterator_value<Iterator>::type value_type;
explicit postfix_increment_dereference_proxy(value_type& x)
: stored_value(x)
public:
explicit postfix_increment_proxy(Iterator const& x)
: stored_iterator(x)
, stored_value(*x)
{}
#endif
// Returning a mutable reference allows nonsense like
// (*r++).mutate(), but it imposes fewer assumptions about the
// behavior of the value_type. In particular, recall that
// (*r).mutate() is legal if operator* returns by value.
// Provides readability of *r++
operator value_type&() const
value_type& operator*() const
{
return this->stored_value;
}
private:
mutable value_type stored_value;
};
template <class Iterator>
class postfix_increment_proxy
{
typedef typename iterator_value<Iterator>::type value_type;
public:
explicit postfix_increment_proxy(Iterator const& x)
: stored_iterator(x)
, dereference_proxy(*x)
{}
postfix_increment_dereference_proxy<value_type> const&
operator*() const
{
return dereference_proxy;
return stored_value;
}
// Provides X(r++)
@@ -206,9 +177,15 @@ namespace iterators {
return stored_iterator;
}
// Provides (r++)->foo()
value_type* operator->() const
{
return boost::addressof(stored_value);
}
private:
Iterator stored_iterator;
postfix_increment_dereference_proxy<value_type> dereference_proxy;
mutable value_type stored_value;
};
@@ -304,6 +281,8 @@ namespace iterators {
template <class Iterator>
class writable_postfix_increment_proxy
{
typedef typename iterator_value<Iterator>::type value_type;
public:
explicit writable_postfix_increment_proxy(Iterator const& x)
: dereference_proxy(x)
@@ -321,6 +300,12 @@ namespace iterators {
return dereference_proxy.stored_iterator;
}
// Provides (r++)->foo()
value_type* operator->() const
{
return boost::addressof(dereference_proxy.stored_value);
}
private:
writable_postfix_increment_dereference_proxy<Iterator> dereference_proxy;
};