Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make_iterator: accept args by value, not forwarding reference, so that passing lvalue iterators works #788

Merged
merged 1 commit into from
Nov 14, 2024

Conversation

oremanj
Copy link
Contributor

@oremanj oremanj commented Nov 13, 2024

This is a reasonable-looking way to expose std::map::equal_range() to Python:

    .def("equal_range", [](MapType& self, KeyType key) {
        auto range = self.equal_range(key);
        return nb::make_iterator(nb::type<MapType>(), "range_iterator", range.first, range.second);
    })

Unfortunately, it dangles: range.first has type MapType::iterator&, so deducing Iterator&& from it yields Iterator = MapType::iterator&, so a reference gets stored in the iterator state object. But that reference refers to the stack-allocated range object, which will be destroyed before the Python iterator is used. This PR changes make_iterator (and friends) arguments to accept their iterator and sentinel by value, to avoid this dangling risk. You can still get reference semantics by specifying the template arguments explicitly.

Also resolve ambiguity between the iterator and range overloads of make_iterator, and clean up the docs to reflect the iterator/sentinel split.

@wjakob
Copy link
Owner

wjakob commented Nov 14, 2024

That seems dangerous indeed. Thank you very much!

@wjakob wjakob merged commit 7f4bae1 into wjakob:master Nov 14, 2024
62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants