#2 and #3 are basically the same thing, don’t const values that are going to be returned. This is basically a subset of the rule not to const things that are going to be moved.
Thank you for #1! I get into arguments all the time with people at work when they want me to const member variables. Now I have a solid resource to point them to from a respected authority.
I'd say 5) Don't take by const reference if you need to keep the value. I see a lot of reflexive `const std::string&` arguments where the string is then copied inside the function. `std::string` in that case is better, since it can be moved into the function, then moved where it needs to go. Perfect forwarding, or adding an overload of `std::string&&` work too. Also, with C++17, there's really no reason for `const std::string&`. Just take `std::string_view`.
Another reason you might not want to do "std::string const &" is exceptions. Though rare, if the copy fails and raises an exception your function is not exception safe. But taking a copy means that the exception happens outside your function and u just move it to where you want inside the function.
Note that returning const value (4) had been advised (e.g. by Scott Meyers) before C++11 and its overloading on value category was introduced in order to prevent assignment to rvalues. Granted, it is hard to defend nowadays but imho still worth to keep it in mind especially when dealing with legacy code.
Just came across with this video. Very helpful, but #1 looks like a "premature optimization". Using const for your members is not a typo, but part of the expressiveness and semantics of your code. So it is worth to mentioning that this is a tradeoff, and if your class can be moved and you are concerned about performance, then removing const will help.
Exactly, it is a bummer that you lose some performance just because you want to have your member const, but it is a cost I am willing to take, to make my code cleaner.
I was close. I thought for sure that #2 was going to be "don't top-level const parameters in a forward declaration", but it was more an extension of #3, and my version of #3 was "don't const things that you intend to be moved from".
Hi! In your #1 point "Do not const member variables", I'm surprised that you didn't talk about "reference member variables" since a reference is a "non assignable" variable, it can be consider as a "const member variable" with some other drawback like the implicit deletion for copy and move assignment and not just the move one.
If I would follow every single rule that Jason defined over the years I would never finish a decent C++ program. It is good to know that such things exist but on the other hand you have customers and deadlines to meet.
about #2, how many times do you create a function that receives an object that wont be changed and you just returns it? (non-rhetorical serious question) I mean, if you change it, it can't be const rendering this point useless but if you don't change it why do you returns it? outside the function the user of the function already has the object.
You might have a conditional that says "return some new thing or returned the thing that was passed into me", but I agree this would be very rare. It's just a thing to be aware of.
Never make your member variables const, they prevent moving. If you don't want anybody to change your members, make them private and only offer const public member functions.
It would be hard to do anything meaningful and correct in them, and the complication is probably not worth the effort. But it's theoretically possible there's a use case there.
@@cppweekly I ask because rule #1 throws some sand at what I do at work. In essence - the use case is that I pass around lots and lots of structs. Which were classes before I dug into it. Basically - what I pass and/or return are structs which have all the data members public _and_ const for ease of access. Each struct defines copy/move operator and a matching constructor. If you want a new one, you are supposed to construct one either from scratch or by destroying an older one. The operators themselves are defined as an explicit call a destructor followed by placement 'new' and a move/copy constructor respectively. It _seems_ that MS compiler does make moves of std::strings in this case but debugging standard library is ... challenging. Now - I admit, I may have overthought this. But I like my m_foo.m_bar.m_member instead of m_foo->GetBar()->GetMember(). From profiling this code I get nice speedups as well.
This may seem a bit of a silly (and unrelated) question and I've tried looking out for answers and haven't gotten any. Is it possible to run Compiler Explorer on my code locally? I know I can generate the assembly instructions and all but it's not the same as having it side by side moving with your code. Or is it? That's what I wanna know, Thanks!
the first example sounded almost like "use copy elision", except... is he saying that if we don't use copy constructor, and we do have a const return type, then the compiler uses copy ASSIGNMENT rather than move assignment?
@@ChaotikmindSrc yes i exagerate a bit but you get my point ;) I love c++, not because it is great, just because i grew up with it. if i would start from scratch today, not sure i would pick it ^^
@@videojeroki Oh well i can relate to that i would hope for an utopic world where some of the c++ horrors just go aways XD The language really feels over-engineered at the moment.
@@ChaotikmindSrc Usually i try to code as clean as possible to make the optimization as simple as possible (preferably someone else) . sometime simple code looks like over engineered indeed. So hopefully this code is pushed and never seen again :D
@@videojeroki I come from a darker place where i was reading assembly before taking a coffee and programming until the sun appears while drinking whisky. Took a long time for me to write "clean code" YMMV I'm partly healed tho ;)
In this case, you could implement your move operations in terms of swap() to avoid breaking the invariant. Doing so would still conform to the standard recommended practice of leaving your moved-from object in a "valid, but unspecified" state.
Only in very rare circumstances. Almost always, the compiler will make its own determination about what is const and what is not by analyzing the code and will optimize based on that regardless of whether you explicitly use const. One case I can think of where const may have a performance benefit is with global values used across translation units. In this situation, the compiler isn’t going to be able to analyze all usages of the variable and so it has to assume that it is non const. If you explicitly mark it as const, the compiler can trust you and use that for some additional optimizations.
Even without multiple translation units, if you mark a static (implicit or explicit) variable const, the compiler can move it to "static initialization" which means you can see a whole range of possible optimizations. I demonstrated this in my CppCon talk ruclips.net/video/zBkNBP00wJE/видео.html
Note: If you remove the puts() calls from struct S constructors and destructors, the compiler can optimize-away many of the bad uses of const. The puts() calls themselves are causing I/O, which forces the compiler to follow the C++ language rules for which ctors/dtors are logically called, to determine the correct output of the program. In other words, the puts() calls you're using for debugging this are causing the extra work, and not the bad const's.
You are over thinking this. The real point you are trying to make is that none of this matters if the types are trivial, which is a fact. I even did an entire conference talk about this specific topic: ruclips.net/video/ZxWjii99yao/видео.html
It makes the code shorter for my purposes. But it's important to know that there is no real difference between the two in C++. It's mostly a style a choice.
@@cppweekly not totally related, but not totally unrelated either: * have u attended/watched the talk about cpp2 titled "Can C++ be 10x Simpler & Safer? - Herb Sutter - CppCon 2022" * to me, it seems its syntax is so similar to Kotlin * but anyways, what are your thoughts on that approach/direction?
100% the wrong take away here. Const member functions have literally nothing to do with const member data *at all* you need to watch my last video on const member functions ruclips.net/video/bqd9ILyQRxQ/видео.html
All effects are fully expected. This video just demonstrates the selected compiller works by standard. It's more interest to see is there some compillers or options to break expectations?
OK cool, thanks. Probably this is also one of the major difference from c++ with almost all the other languages. I remember in at least js and python, people are recommended to use const as possible, but const seems not to help in cpp. They are too different. Probably anything like 4 to 20 bytes can be const without any significant trouble because their ctor or copy are almost the same size, but if the object is bigger, then I guess the const keyword messes.
As I started the video with, you should use const almost everywhere. These are the exact 4 times to NOT use const. They help with readability, correctness, and in some places performance.
@@cppweekly OK. Thanks. I've been away from c++ for years. I saw people battle with the grammars with these tricks only to get the compiler to do specific jobs. If people can script for the compiler and specify the concrete behavior for the compiler, most the tricks against the compiler would be gone. I remember in another video, you mentioned the constexpr causes a lot trouble. If it had another layer, it would be like: {"compiler instructions"; compile_time_const.push_back("some_variable") } int main(){ const int some_variable = make_value(...); } I tried to tell people of this idea but no one cares.
Looks like YT deleted my comment, but the gist of it was, I love your videos because they help me learn more about C++ and keep my skills with it up to date. However, they also give me more ammunition in my crusade against C++ because it is still a language I vehemently dislike. I wish more people would just use C and for fancy syntactic sugar, create a language that's better than C++, so not Rust.
C programmers are sadistic masochists. I didn't realize there were so many ways you could break the code. I'll stick with Turbo Pascal for short programs and Delphi for larger programs (minus Object programming, of course.)
This language is really really awful (and before anyone says something about it, I have been programming professionally in C++ for more than 30 years). I can't believe that for every sentence I write I have to check what the compiler emits at low level 😱
Nothing forces you to check this. Other compiled languages are going to have similar issues where a small change can drastically change the compiled representation. I see plenty of videos just like this for c# that explore how tiny changes can have huge impacts on the generated code. IMO, this is the reality of compiled languages - they tend to be so much higher level than what they compile into that you are going to have these kinds of situations. I think we talk about these issues in c++ more because c++ programmers tend to love to squabble about low level optimizations like this. I haven’t reached your level of experience yet, but in my 12 years of c++ experience I have never looked at the generated assembly of something I wrote. I am probably missing out on some performance somewhere… but I am having no issues meeting some pretty strict performance requirements (DSP and real-time data visualization).
#2 and #3 are basically the same thing, don’t const values that are going to be returned. This is basically a subset of the rule not to const things that are going to be moved.
Thank you for #1! I get into arguments all the time with people at work when they want me to const member variables. Now I have a solid resource to point them to from a respected authority.
I'd say 5) Don't take by const reference if you need to keep the value. I see a lot of reflexive `const std::string&` arguments where the string is then copied inside the function. `std::string` in that case is better, since it can be moved into the function, then moved where it needs to go. Perfect forwarding, or adding an overload of `std::string&&` work too.
Also, with C++17, there's really no reason for `const std::string&`. Just take `std::string_view`.
There's a few reasons I can think of, e.g. when passing it in to an api taking null-terminated strings.
@@baardi2 Yup, std::string_view with null-terminated strings is a pretty annoying combination.
Another reason you might not want to do "std::string const &" is exceptions. Though rare, if the copy fails and raises an exception your function is not exception safe. But taking a copy means that the exception happens outside your function and u just move it to where you want inside the function.
@@baardi2 I hope in the future a sort of "zstring" (the term for a view of a string that's null-terminated) can become part of the STL
@@ChiliTomatoNoodle What about adding the null terminator when passing to those APIs? does that defeat the efficiency afforded by string_view?
#1 sounds disappointing. I find of value to set a member variable to be const when you are intending not to modify it. This is a negative side effect.
Note that returning const value (4) had been advised (e.g. by Scott Meyers) before C++11 and its overloading on value category was introduced in order to prevent assignment to rvalues. Granted, it is hard to defend nowadays but imho still worth to keep it in mind especially when dealing with legacy code.
Just came across with this video. Very helpful, but #1 looks like a "premature optimization". Using const for your members is not a typo, but part of the expressiveness and semantics of your code. So it is worth to mentioning that this is a tradeoff, and if your class can be moved and you are concerned about performance, then removing const will help.
Exactly, it is a bummer that you lose some performance just because you want to have your member const, but it is a cost I am willing to take, to make my code cleaner.
@@TrueWodzu why not make a CONST macro and define it only on debug build? Wouldnt that be ideal?
I was close. I thought for sure that #2 was going to be "don't top-level const parameters in a forward declaration", but it was more an extension of #3, and my version of #3 was "don't const things that you intend to be moved from".
Hi!
In your #1 point "Do not const member variables", I'm surprised that you didn't talk about "reference member variables" since a reference is a "non assignable" variable, it can be consider as a "const member variable" with some other drawback like the implicit deletion for copy and move assignment and not just the move one.
I was expecting some info regarding this, although I think this is out of context on the video. But a note is definitely appreciated.
Yes, you're both correct, and I also avoid reference member variables, but not the point of this video.
If I would follow every single rule that Jason defined over the years I would never finish a decent C++ program. It is good to know that such things exist but on the other hand you have customers and deadlines to meet.
about #2, how many times do you create a function that receives an object that wont be changed and you just returns it? (non-rhetorical serious question)
I mean, if you change it, it can't be const rendering this point useless
but if you don't change it why do you returns it? outside the function the user of the function already has the object.
Convinience? Especially if the object has complex initialization and we don't want code duplication.
You might have a conditional that says "return some new thing or returned the thing that was passed into me", but I agree this would be very rare. It's just a thing to be aware of.
@@cppweekly that's a great answer.
Never make your member variables const, they prevent moving. If you don't want anybody to change your members, make them private and only offer const public member functions.
Yup, that's in the video.
7:27 whats clang-tidy?
Regarding rule #1.
What about classes/structures which explicitly define move assignment and constructor?
It would be hard to do anything meaningful and correct in them, and the complication is probably not worth the effort.
But it's theoretically possible there's a use case there.
@@cppweekly
I ask because rule #1 throws some sand at what I do at work. In essence - the use case is that I pass around lots and lots of structs. Which were classes before I dug into it. Basically - what I pass and/or return are structs which have all the data members public _and_ const for ease of access. Each struct defines copy/move operator and a matching constructor. If you want a new one, you are supposed to construct one either from scratch or by destroying an older one.
The operators themselves are defined as an explicit call a destructor followed by placement 'new' and a move/copy constructor respectively. It _seems_ that MS compiler does make moves of std::strings in this case but debugging standard library is ... challenging.
Now - I admit, I may have overthought this. But I like my m_foo.m_bar.m_member instead of m_foo->GetBar()->GetMember(). From profiling this code I get nice speedups as well.
This may seem a bit of a silly (and unrelated) question and I've tried looking out for answers and haven't gotten any. Is it possible to run Compiler Explorer on my code locally? I know I can generate the assembly instructions and all but it's not the same as having it side by side moving with your code. Or is it? That's what I wanna know, Thanks!
You certainly can, set up a local instance and include your own directories. It's a bit tricky sometimes, but should work out.
@@cppweekly thanks Jason, I’ll give that a shot.
the first example sounded almost like "use copy elision", except...
is he saying that if we don't use copy constructor, and we do have a const return type, then the compiler uses copy ASSIGNMENT rather than move assignment?
Is it worth avoiding const data members of a class if it isn't copyable at all?
if you have explicit disabled copy and move, then it's irrelevant
Great insight. 10/10
When you pick C++ for performance reasons and you find out that a single trivial const "error" make your effort irrelevant...
I wouldn't go that far, it is certainly better to be aware of that, but you can still get very good perf comparing to other languages
@@ChaotikmindSrc yes i exagerate a bit but you get my point ;)
I love c++, not because it is great, just because i grew up with it. if i would start from scratch today, not sure i would pick it ^^
@@videojeroki Oh well i can relate to that
i would hope for an utopic world where some of the c++ horrors just go aways XD
The language really feels over-engineered at the moment.
@@ChaotikmindSrc Usually i try to code as clean as possible to make the optimization as simple as possible (preferably someone else) .
sometime simple code looks like over engineered indeed. So hopefully this code is pushed and never seen again :D
@@videojeroki I come from a darker place where i was reading assembly before taking a coffee and programming until the sun appears while drinking whisky.
Took a long time for me to write "clean code" YMMV
I'm partly healed tho ;)
Thanks video
const first
Strictly speaking, moving from an object may break an invariant:
template
struct WithAtLeastOne{
explicit WithAtLeastOne(typename Container::value_type&& obj) {
data.push_back(std::move(obj));
}
private:
Container data;
};
??
Isn't that the moment when rule of 5 should be used instead of relying on default implementations?
In this case, you could implement your move operations in terms of swap() to avoid breaking the invariant. Doing so would still conform to the standard recommended practice of leaving your moved-from object in a "valid, but unspecified" state.
U r the best👌
Is there any case we must use const to avoid performance issue (not human error)?
Only in very rare circumstances. Almost always, the compiler will make its own determination about what is const and what is not by analyzing the code and will optimize based on that regardless of whether you explicitly use const. One case I can think of where const may have a performance benefit is with global values used across translation units. In this situation, the compiler isn’t going to be able to analyze all usages of the variable and so it has to assume that it is non const. If you explicitly mark it as const, the compiler can trust you and use that for some additional optimizations.
Even without multiple translation units, if you mark a static (implicit or explicit) variable const, the compiler can move it to "static initialization" which means you can see a whole range of possible optimizations.
I demonstrated this in my CppCon talk ruclips.net/video/zBkNBP00wJE/видео.html
Is it possible to detect all such cases automatically?
not with any tools that I know of.
can't you move construct const values? Granted that you write your own move constructor, I would say it's not too bad to have const members no?
you can `const auto value = std::move(othervalue)`
but you cannot `const auto value = std::move(someconstvalue)` in any way that makes logical sense.
Note: If you remove the puts() calls from struct S constructors and destructors, the compiler can optimize-away many of the bad uses of const. The puts() calls themselves are causing I/O, which forces the compiler to follow the C++ language rules for which ctors/dtors are logically called, to determine the correct output of the program. In other words, the puts() calls you're using for debugging this are causing the extra work, and not the bad const's.
You are over thinking this.
The real point you are trying to make is that none of this matters if the types are trivial, which is a fact. I even did an entire conference talk about this specific topic:
ruclips.net/video/ZxWjii99yao/видео.html
0:51 any reason why you are using struct objects rather than class objects?
It makes the code shorter for my purposes.
But it's important to know that there is no real difference between the two in C++. It's mostly a style a choice.
@@cppweekly not totally related, but not totally unrelated either:
* have u attended/watched the talk about cpp2 titled "Can C++ be 10x Simpler & Safer? - Herb Sutter - CppCon 2022"
* to me, it seems its syntax is so similar to Kotlin
* but anyways, what are your thoughts on that approach/direction?
If I dont const ANY member data, this would ultimately result into not using const member functions... So "Almost never use const" then? ;)
100% the wrong take away here. Const member functions have literally nothing to do with const member data *at all*
you need to watch my last video on const member functions ruclips.net/video/bqd9ILyQRxQ/видео.html
All effects are fully expected. This video just demonstrates the selected compiller works by standard. It's more interest to see is there some compillers or options to break expectations?
OK cool, thanks. Probably this is also one of the major difference from c++ with almost all the other languages. I remember in at least js and python, people are recommended to use const as possible, but const seems not to help in cpp. They are too different.
Probably anything like 4 to 20 bytes can be const without any significant trouble because their ctor or copy are almost the same size, but if the object is bigger, then I guess the const keyword messes.
As I started the video with, you should use const almost everywhere. These are the exact 4 times to NOT use const. They help with readability, correctness, and in some places performance.
@@cppweekly OK. Thanks. I've been away from c++ for years. I saw people battle with the grammars with these tricks only to get the compiler to do specific jobs. If people can script for the compiler and specify the concrete behavior for the compiler, most the tricks against the compiler would be gone. I remember in another video, you mentioned the constexpr causes a lot trouble. If it had another layer, it would be like:
{"compiler instructions";
compile_time_const.push_back("some_variable")
}
int main(){
const int some_variable = make_value(...);
}
I tried to tell people of this idea but no one cares.
Looks like YT deleted my comment, but the gist of it was, I love your videos because they help me learn more about C++ and keep my skills with it up to date. However, they also give me more ammunition in my crusade against C++ because it is still a language I vehemently dislike. I wish more people would just use C and for fancy syntactic sugar, create a language that's better than C++, so not Rust.
have u watched the video about cpp2 presented in cpp-con2022 which talked about backword compatibility only on demand. It was solid.
It's crazy that a 2022 compiler is not smart enough to know that a local const value which will be be out of scope on return should be moved
you cannot MOVE a CONST because it is a Constant!
At best it could be elided, but never ever moved. ruclips.net/video/ZKaoR3dP9uM/видео.html
I can't wait to use const in all of these places
C programmers are sadistic masochists. I didn't realize there were so many ways you could break the code. I'll stick with Turbo Pascal for short programs and Delphi for larger programs (minus Object programming, of course.)
This language is really really awful (and before anyone says something about it, I have been programming professionally in C++ for more than 30 years). I can't believe that for every sentence I write I have to check what the compiler emits at low level 😱
Nothing forces you to check this. Other compiled languages are going to have similar issues where a small change can drastically change the compiled representation. I see plenty of videos just like this for c# that explore how tiny changes can have huge impacts on the generated code. IMO, this is the reality of compiled languages - they tend to be so much higher level than what they compile into that you are going to have these kinds of situations.
I think we talk about these issues in c++ more because c++ programmers tend to love to squabble about low level optimizations like this.
I haven’t reached your level of experience yet, but in my 12 years of c++ experience I have never looked at the generated assembly of something I wrote. I am probably missing out on some performance somewhere… but I am having no issues meeting some pretty strict performance requirements (DSP and real-time data visualization).