I am trying to write a class function which accepts boost::any_range
which is a double-random access range. My purpose is to be able to pass any kind of that range to the function which can be an std::vector
, std::deque
, or a boost range. The code works for std::vector
and std::deque
, however it gives a warning when I try with a boost range.
I tried this:
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/any_range.hpp>
#include <iostream>
#include <iterator>
#include <vector>
using Range = boost::any_range<const double, boost::random_access_traversal_tag, const double>;
struct Indexer {
Indexer(const double param_) : param(param_) {}
double operator()(const int i) const
{
return static_cast<double>(i) + param;
}
private:
const double param;
};
class Temp {
public:
void workWithAnyRange(const Range& range) {
workWithAnyRangeTemplated(range);
}
private:
template<typename R>
void workWithAnyRangeTemplated(const R& r) {
for (auto i : r) {
std::cout << "i: " << i << std::endl;
}
}
};
int main() {
Temp temp;
temp.workWithAnyRange(std::vector<double>{1,2,3});
temp.workWithAnyRange(std::deque<double>{1,2,3});
temp.workWithAnyRange(boost::irange(0, 10) | boost::adaptors::transformed(Indexer(15.0))); //introduces the warning
return 0;
}
And the following output I got:
In file included from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator.hpp:22:0,
from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/any_range.hpp:17,
from <source>:5:
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function 'boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference() const [with WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>; Reference = double; Difference = long int; Buffer = boost::any_iterator_buffer<64ul>; boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&]':
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:57: warning: function returns address of local variable [-Wreturn-local-addr]
return dereference_cast<reference>(*m_it);
^
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:51: note: declared here
return dereference_cast<reference>(*m_it);
^
ASM generation compiler returned: 0
In file included from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator.hpp:22:0,
from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/any_range.hpp:17,
from <source>:5:
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function 'boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference() const [with WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>; Reference = double; Difference = long int; Buffer = boost::any_iterator_buffer<64ul>; boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&]':
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:57: warning: function returns address of local variable [-Wreturn-local-addr]
return dereference_cast<reference>(*m_it);
^
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:51: note: declared here
return dereference_cast<reference>(*m_it);
^
Execution build compiler returned: 0
Program returned: 0
i: 1
i: 2
i: 3
i: 1
i: 2
i: 3
i: 15
i: 16
i: 17
i: 18
i: 19
i: 20
i: 21
i: 22
i: 23
i: 24
As you see, it outputs something but the warning seems concerning. If I remove the line where I called the function with boost::irange
, the warning disappears. Can anyone help me to resolve the issue?
I got the feeling that I messed up with the compiler options, because this seems like it works – user1508716 4 mins ago
Nah, that's just because that includes the boost include directory with -isystem
instead of -I
hiding the warnings.
The warning indicates that the result of the transform - an rvalue - is returned by reference. Rather surprising since you requested the reference type to be double const
. Indeed, the error message confirms:
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function '
boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference()
const [with
WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>;
Reference = double;
Difference = long int;
Buffer = boost::any_iterator_buffer<64ul>;
boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&;
]':
Note how it comfirms that Reference = double
as you requested (top-level const is not significant in function signatures in C++). However, it deems boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&
, making the implementation of dereference
unsafe:
virtual reference dereference() const
{
return dereference_cast<reference>(*m_it);
}
Comparing with Boost 1.81.0 shows no problem: https://godbolt.org/z/9qfTzn15T
Indeed boost 1.74.0 contains a fix: https://godbolt.org/z/vEe118f6G
Indeed boost 1.73.0 still had the problem: https://godbolt.org/z/EM56Pss5q
The change involved appears to be
474efda Merge pull request #94 from mjendruk/fix-any-range-non-reference-references
Which links to https://github.com/boostorg/range/pull/94 "Fix any_range with non-reference references can cause UB"