-
Notifications
You must be signed in to change notification settings - Fork 9.1k
- moving string parameter into data member instead of copying it. #1899
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
Conversation
- removing noexcept from methods where an exception could be raised. If std::terminate() call is desired instead, I guess those should be left and std::move_if_noexcept() used to document the fact that it's on purpose. - std::moving local variable into argument when possible. - change maxversiontested XML element to maxVersionTested. - used of gsl::narrow_cast where appropriate to prevent warnings. - fixed bug in TerminalSettings::SetColorTableEntry()
zadjii-msft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mostly have some questions, otherwise this largely looks fine.
| { | ||
| auto pwshProfile{ _CreateDefaultProfile(L"PowerShell Core") }; | ||
| pwshProfile.SetCommandline(psCoreCmdline); | ||
| pwshProfile.SetCommandline(std::move(psCoreCmdline)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiousity, how does line 206 (above) work?
powershellProfile.SetCommandline(L"powershell.exe");Does it create a new wstring using the string literal to initialize it, then immediately move it to the function call? (not saying this is wrong, I just don't know)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Precisely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, this effectively means that if the creation of the string raises an exception, it will happen at the call site, in CascadiaSettings::_CreateDefaultProfiles(), not in Profile::SetCommandLine() (which is rightfully noexcept).
src/cascadia/TerminalApp/App.cpp
Outdated
|
|
||
| // If we don't have that many profiles, then do nothing. | ||
| if (realIndex >= profiles.size()) | ||
| if (realIndex >= gsl::narrow_cast<decltype(realIndex)>(profiles.size())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason to use decltype(realIndex) over manually stating the type of realIndex?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the type is changed for any reason, one would not need to also change that line.
That said, this was a small mistake as I should have used gsl::narrow instead. It will raise an exception if the cast would change the value in any way. (see gsl_util).
I'll wait for you feedback to make the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems correct to me. I love decltype.
src/cascadia/TerminalApp/Profile.cpp
Outdated
| void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept | ||
| { | ||
| _schemeName = schemeName; | ||
| static_assert(noexcept(_schemeName = std::move(schemeName))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait what does this do? I don't think I'm familiar with using noexcept() as a function like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've only been using it a couple of times myself. 😉
See noexcept operator.
It just documents the fact that line 450 does not raise any exception. If anything changes in std::optional or std::wstring implementations and an exception could be raised, line 449 would effectively raise an error during build time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My opinion only 😄 - although 100% correct - code that checks to see if standard C++ code is C++ complaint is overkill and adds unnecessary complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we shouldn't need to validate that C++ code is C++ compliant!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
FWIW, it's about the implementation of the std::optional move constructor which I believe was not marked as noexcept till C++ 17.
I find that static_assert statement to be easier than starting to read the C++ standard. ;-)
| void Profile::SetIconPath(std::wstring_view path) noexcept | ||
| void Profile::SetIconPath(std::wstring_view path) | ||
| { | ||
| static_assert(!noexcept(_icon.emplace(path))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to the above, what's this doing and why does this one have a ! in it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the flip side of the previous comment. Maybe it'd be clearer if I'd had the comment for each static_assert:
static_assert(noexcept(_schemeName = std::move(schemeName)), "Profile::SetColorScheme() is no longer noexcept!")
static_assert(!noexcept(_icon.emplace(path)), "Mark Profile::SetIconPath() as noexcept");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea a comment might be helpful, since I definitely read that code and assumed that it was asserting the opposite :P
src/cascadia/TerminalApp/App.cpp
Outdated
|
|
||
| // If we don't have that many profiles, then do nothing. | ||
| if (realIndex >= profiles.size()) | ||
| if (realIndex >= gsl::narrow_cast<decltype(realIndex)>(profiles.size())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems correct to me. I love decltype.
src/cascadia/TerminalApp/Profile.cpp
Outdated
| void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept | ||
| { | ||
| _schemeName = schemeName; | ||
| static_assert(noexcept(_schemeName = std::move(schemeName))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we shouldn't need to validate that C++ code is C++ compliant!
| // Arguments: | ||
| // - path: the path | ||
| void Profile::SetIconPath(std::wstring_view path) noexcept | ||
| void Profile::SetIconPath(std::wstring_view path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious here. This one uses wstring_view, and the others use wstring. Should we standardize on just one? If so, what do you think we should do, @yves-dolce?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the body of the method (e.g. Profile::SetIconPath) calls methods that support std::wstring_view, std::wstring_view will allow you not to have any heap allocation during the parameter passing. That class is just a pointer and a size after all.
But keep in mind that:
- it does not enforce the string to be null terminated. Again, it's just a pointer to the beginning of the string and a length.
- the compiler might have a harder time optimizing the calling site as now, you've created an alias. When you were taking a
std;:wstring, no aliasing was created.
All in all, I'd personally stick with std::wstring, and std::move. I use std::wstring_view if I plan on having to interact with code that uses weird stuff and don't want to force heap allocation... (CString, bstr_t, CComBSTR, ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough! 👍
|
This is the first time I participate on an GitHub open source project. |
|
That's correct! |
|
I pushed without compiling as my changes were very small. |
|
I believe you just need to Clean your local build and make sure you "restore nuget packages" again; our dependencies have been updated 😄 |
| // Arguments: | ||
| // - path: the path | ||
| void Profile::SetIconPath(std::wstring_view path) noexcept | ||
| void Profile::SetIconPath(std::wstring_view path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough! 👍
| <!-- Windows 10 1903 --> | ||
| <!-- See https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/xaml-islands --> | ||
| <maxversiontested Id="10.0.18362.0"/> | ||
| <maxVersionTested Id="10.0.18362.0"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm moderately worried about whether this is case sensitive. I'll check with the manifest team.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. I'm curious about that one as XML is case sensitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wellp, it looks like it is case-sensitive. Somebody owes me a coke, I just haven't figured out who.
|
Are we just waiting for a 2nd reviewer? |
zadjii-msft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with this, but since @DHowett-MSFT left some other comments, I'll let him be the second on this one.
| void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept | ||
| { | ||
| _schemeName = schemeName; | ||
| _schemeName = std::move(schemeName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, this works with a std::optional too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Blurb from cppreference.
Move constructor: If other contains a value, initializes the contained value as if direct-initializing (but not direct-list-initializing) an object of type T with the expression std::move(*other) and does not make other empty: a moved-from optional still contains a
value, but the value itself is moved from. If other does not contain a value, constructs an object that does not contain a value. This constructor does not participate in overload resolution unless std::is_move_constructible_v is true. It is a trivial constructor if std::is_trivially_move_constructible_v is true.
So in this case std::move() will cast the variable (schemeName) to an rvalue, allowing it to bind to a move constructor.
|
@DHowett-MSFT, this one is also waiting for you and otherwise looks good to go. |
DHowett-MSFT
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm quite comfortable with this now. Thank you for your contribution, and sorry it took us so long!
noexceptfrom methods where an exception could be raised.If
std::terminate()call is desired instead, I guess those should beleft and
std::move_if_noexcept()used to document the fact that it'son purpose.
std::movelocal variable into argument when possible.maxversiontestedXML element tomaxVersionTested.gsl::narrow_castwhere appropriate to prevent warnings.TerminalSettings::SetColorTableEntry()Summary of the Pull Request
References
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed