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

Fix modernize-loop-convert warning reported by clang-tidy #1112

Conversation

MaximSmolskiy
Copy link
Contributor

Fix #1095

@@ -137,8 +137,8 @@ std::vector<rocksdb::Status> String::MGet(const std::vector<Slice> &keys, std::v
// don't use range-based for loop here, coz the slice member
// would refer the address instead of copy the value, and use
// range-based for loop may cause all members refer to the same addr
for (size_t i = 0; i < ns_keys.size(); i++) {
slice_keys.emplace_back(ns_keys[i]);
for (const auto &ns_key : ns_keys) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaximSmolskiy This place is really tricky. The comment above it explains why we should NOT use a range-based loop here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@torwig Can you please explain this comment in more details?
ns_keys is std::vector<std::string>. std::vector operator[](size_type pos) always returns reference (as said here), so ns_keys[i] was reference to std::string. And I don't understand how range-based for loop can cause problems here, because ns_key now is reference to std::string too (as it was).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emplace_back will invalidate all references and iterators (if capacity changes), so it is not allowed to use an iterator or reference based loop (as well as for-range) here. Of cource, index is always safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PragmaTwice I'm sorry, but I still don't understand what the problem is. Here we iterate through vector ns_keys and put its values to another vector slice_keys. So, ns_keys shouldn't be updated during this loop. So, range-based for loop should be equivalent to index based loop here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry. I did not notice that there are two different vectors. Some time to wait me to understand these code again 🤣

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I cannot understand the comment. Slice will never copy a string, it will only take reference to a string. cc @git-hulk @ShooterIT

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just tested the following code:

std::vector<std::string> ns_keys = {"one", "two", "three", "four"};
std::vector<rocksdb::Slice> slice_keys;
for (size_t i = 0; i < ns_keys.size(); i++) {
  slice_keys.emplace_back(ns_keys[i]);
}

for (auto key : slice_keys) {
  std::cout << key.ToString() << std::endl;
}

And the output is:

one
two
three
four

Then I changed it to (as in the clang recommendation):

std::vector<std::string> ns_keys = {"one", "two", "three", "four"};
std::vector<rocksdb::Slice> slice_keys;
for (auto &ns_key : ns_keys) {
  slice_keys.emplace_back(ns_key);
}

for (auto key : slice_keys) {
  std::cout << key.ToString() << std::endl;
}

And the output is still the same.
Perhaps at some point in time, the code in kvrocks was changed but the comment is still here (an doutdated). Or there is something else.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be something like:

std::vector<rocksdb::Slice> slice_keys(ns_keys.size());
std::copy(ns_keys.begin(), ns_keys.end(), slice_keys.begin());

Copy link
Member

@git-hulk git-hulk Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PragmaTwice @torwig @MaximSmolskiy If my memory serves, the root cause is the for loop would reuse the same variable ns_key address if we use for (auto ns_key : ns_keys) instead of for (auto &ns_key : ns_keys).

So we can remove this comment if for (auto &ns_key : ns_keys) works well.

@PragmaTwice
Copy link
Member

I think we can still use range-based for loop and remove these comment to continue with this PR if it is confirmed that these comments are out-of-date and not correct now.
cc @git-hulk

@PragmaTwice
Copy link
Member

Thanks for your contribution!

@PragmaTwice PragmaTwice merged commit 0c4d4b7 into apache:unstable Nov 16, 2022
@MaximSmolskiy MaximSmolskiy deleted the fix-modernize-loop-convert-warning-reported-by-clang-tidy branch November 16, 2022 07:01
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.

Fix modernize-loop-convert warning reported by clang-tidy
4 participants