If each of the core guidelines had a video like this with you explaining them I'm sure C++ would be a lot easier for a lot of people :) Thanks for the in depth explanation and the consideration of different C++ standards for the code examples! #clion
This was great! There are a lot of people who make very basic or very advanced programming videos, but you are amazing at intermediate level content. Keep up the great work.
Even when I have scoped lock available, I prefer lock guard for when you are only locking exactly one mutex. I feel it shows clearer intent, and also you get a compiler error if you forget to give it the mutex. You don't get that with scoped lock as no mutex is a valid initialisation. Would love to know if there are any downsides to this approach. #clion
Eventually, I hope tooling like clang-tidy would warn on explicit zero-argument scoped_lock, but for now I think it's perfectly reasonable to continue using lock_guard to avoid this potential (and reasonable) human error.
Manual flushing expresses intent much better than endl anyway. Sometimes you want to flush (ex. when you're writing a logger or test where the app could terminate after the write but before the stream is destroyed/auto-flushed). Thanks for the video ☺️ #clion
Been really enjoying your videos, especially your recent dive into an assortment of C++ topics. I ended up purchasing the book Effective Modern C++ because of your video outlining nooby C++ habits, most of which were applicable to my traditional "C style" approach to programming in C++. About a quarter of the way through the book, and learning a bunch. Thanks! #clion
In most c++ implementations, streams are already thread safe. The reason this example creates garbage output is because of how the output is generated with multiple calls to operator
True! cout, cin, etc... are required by the standard to be thread-safe (unless sync_with_stdio(false) is used), and most implementations implement file streams in a thread-safe way, even though thread-safety is only a requirement (by the standard) for cout, cin, etc... but not file streams, so indeed a local stringstream is a decent solution. For user-defined ostreams, of course all bets are off with this approach, and I bet that stringstream itself is not thread-safe (case when ostream passed is a stringstream) , so I would still recommend one of the methods in the video for that reason. I would also say that if you are using C++20 and taking the osyncstream approach, the code looks very similar to your stringstream approach and doesn't require the os
Awesome video as always! 07:21 1. a batch writing (every 1000 lines) is a risk to loose a batch 2. isn't synchronized queue will do the same with a mutex under the hood?
Thanks! 1. Potentially yes, more in the situation of a long lived process that writes infrequently. Handling failed writes is a much more complex topic that has a few decent solutions depending on the situation. Although, a common theme of the solutions is actually point 2! 2. Yes under the hood there will still need to be synchronization, but this centralizes the place where writing happens, making it easier to attempt to handle things like failed writes. It is more of an organizational construct to help keep your architecture clean.
There is a potential the compiler could avoid the machinery of calling a function (although neither clang nor gcc does in this case, see godbolt.org/z/cqEnP1Whs ), however, the compiler cannot optimize away a flush due to it's nature of causing a side-effect.
this was great! as a TA for a data structures course, I've always taught the use of std::endl; knowing it flushes the buffer but not considering the impact on large-scale performance. I'll make sure to integrate use of now. The multithreading examples were fascinating. thank you! #clion
Yes this is good to keep in mind. Funnily enough, the core guideline right before "avoid endl" is "SL.io.10: Unless you use printf-family functions call ios_base::sync_with_stdio(false)" ( isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#slio10-unless-you-use-printf-family-functions-call-ios_basesync_with_stdiofalse ). So it is actually recommended to give up the atomicity of std::cout for performance reasons. But, if you are aware of the atomicity guarantee and are mindfully depending on it, then I wouldn't necessarily be opposed. Thanks for mentioning!
@L. Kärkkäinen Funny enough, for this exact reason std::cerr flushes *everything* immediately, so you effectively still don't need any flush/endl at all. For regular logging use std::clog which also prints to stderr but does not flush automatically.
The single call being safe is actually true! But only for std::cout and the like. This is not guaranteed for arbitrary ostreams, such as file streams. Under the hood osyncstream typically uses a mutex.
I was wondering why everyone added #clion in their comments, and then I read the description of the video... I saw where that myth was comming, but I enjoyed all the video from start to end. As someone who used C++ heavily when C++11 was still a new thing, I was curious to know how is the standard about multithreading today. Thank you for your content, mCoding!
So I'm curious, what is std::endl used for then? I'm not too familiar with C++, but I always just assumed it was a way to get the system dependent line separator (containing a carriage return on some systems). If there's no legitimate use for it, can it be deprecated?? #clion
I wasn’t sure if it could help or not, because I didn’t know if some of the relevant buffers were thread-local, but I knew enough to not trust it completely. Also I’ve wanted to try #clion for a while.
What's the syntax with the curly braces called? Like in `std::ofstream file{"out.txt"}` what are the curly braces doing? I'm somewhat used to c++ through Qt, but I don't think I've seen this syntax before
Hey James! Im currently a high school senior and very advanced in Python. I would like to learn C++ but don't really know where to start. I know the basics (pretty much C) but modern C++ is a little too much for once. Do you know a great ressource where I can learn it?
Hi there! I would reccomend finding an online free pdf of "The c++ programming language" by barne stroustrup. You should be able to get one for c++11 free online, don't forget earlier then c++11.
Thanks for explaining and std::endl in depth, it was indeed virtually impossible to find an explanation I’d understand/believe until now. I’d also love to use #clion on my Mac. I’m not into text editors for C++ in MacOS.
thanks for your videos. do you think you could do some videos on programming enviroments? text editor + compiler + debugger + build system + meta build system? #clion
Great stuff as always! As a primarily C developer, I always enjoy learning about the features in C++ that I should be using but never know about, keep up the good work! #clion
Ok then. Why we have std::endl in C++, if it's usage is discouraged? Isn't that weird that at the first glance simple end-of-line constant turned out to be flushing operation? What's the original purpose in that? #clion
As is the case with many things in C++, it was chosen long long ago before the implications were fully understood and at a time where the constraints of the hardware were very different from what they are today. And, for backwards compatibility, it cannot be changed, ever.
I'm really glad that you've been making a lot more C++ content lately, as your Python videos were already top-notch, and this kind of deeper approach is especially useful with a language as versatile as C++. You don't just explain why something should be avoided or doesn't work, but you always offer multiple solutions as well. Thank you! 😄#clion
Indeed, std::cout has special wording in the standard that actually guarantees that this would work, see en.cppreference.com/w/cpp/io/cout for a brief explanation. Of course, if you are writing to a file you're out of luck!
for this short example, I would build the string then write into Ostrem as a whole so that competition would not alter the inner order of every single line #clion
Suppose you want to display a line of information to the user immediately, you don't want to wait until a buffer fills to display it (perhaps printing this info is rare and it would take a while to fill), you want to display NOW. Then you should use endl because you intend to flush. This is mostly unnecessary since cout is usually line-buffered anyway, but it doesn't _have_ to be line-buffered. Also, whether or not cout is already line-buffered, using endl signals to readers of your code that you _intend_ to flush immediately.
Though it's not the main the point of the video, I actually ended up learning a lot more about multithreaded programming in general than I did before. Thank you. #clion
This brings some great memories, i moved away from c++ (yes yes, heresy) but every time I see your videos it makes me want to get back :) #clion for the win :D
Thanks for your stellar videos. Home sick bc the holidays, and your videos are helpful both in coding and helping me get passed my rut. Thanks again. Also, #clion
Love it! C++ really isn't as hard as people made it out to be when I first started, and videos like this really help me getting more and more into programming #clion
Well, for a teacher I can understand that what you teach your students doesn't necessarily focus on best practices. Sometimes it's not worth it to explain a best practice if the benefit is not core to the lesson and would take a lot of time. Hopefully your teacher is already on board, or feel free to send them this video :)
Yes! But I'm itching for better compiler support before recommending it yet. I will make a video about it once the major compilers all have it working in a stable version that most of my viewers would be able to upgrade to easily.
i don't even write C++ (more of a kotlin/java and python guy) but i appreciate these videos anyway. thanks for randomly choosing me to have #clion by the way, really appreciate it
I always liked c++ since it was my first programming language but I did not go deep with it. Your videos are really helpful for me to learn more. #clion
I believe std::endl should portably allow Windows carriage return line feed pattern. Also auto flush on newline is a common feature of various buffered OS objects like stdout or stderr. Therefore flushing is sometimes automatic and unavoidable. As for thread safety of the OS write and read calls, likely they are thread safe. So all the C++ nonsense here though useful is far from the only perspective on the issue. He left out the C and raw OS library perspective.
std::endl does not produce a carriage return on Windows. It produces a newline then flushes on all platforms, as required by the standard. While auto flush on newline may happen for certain stream, it does not happen for all of them, especially not file or string streams, and in these cases endl is often a common and significant performance slowdown. The advice to avoid endl is not my personal vendetta, it is time tested battle proven advice even recommended in the C++ core guidelines maintained by Bjarne, creator of C++: isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rio-endl. I don't talk about C in this video because this is a C++ video about a specific misconception about std::endl, not a how to guide for printing across different languages. C is a different language than C++ and it does not have std::endl.
@mCoding in Java the System.LineSeparator does give a OS specific newline. Didnt know C++ standardized the Linux variant. Interesting reference thanks! Indeed the lower level stuff is another topic. But one which although you understand, many don't.
I recently worked on some distributed computing code in which I found out this myth was totally false, thankfully it only really needed to return data at the end of the process. So I flushed all the debug and printing info into a string stream printed them from the managing thread. #clion
Teaching is hard, sometimes professors say things that are good approximations for learners or are otherwise helpful simplications for the classroom allowing them to skip longer explanations and allow the class to spend precious time on more important topics. Since the biggest difference is worse performance using endl, I can understand that a beginner class (the kind where you would be learning what endl is) would not be concerned much with performance, so it would be simpler to just tell you to use endl and move on.
I like to use the following rule of thumb for deciding when to flush the buffer: if it's yellow, let it mellow, if it's brown, flush it down.
If each of the core guidelines had a video like this with you explaining them I'm sure C++ would be a lot easier for a lot of people :) Thanks for the in depth explanation and the consideration of different C++ standards for the code examples! #clion
I don't think I've ever seen better and more concise videos on CPP and Python topics anywhere else, so bravo for that! #clion
Many thanks, I'm glad you enjoy!
This was great! There are a lot of people who make very basic or very advanced programming videos, but you are amazing at intermediate level content.
Keep up the great work.
Even when I have scoped lock available, I prefer lock guard for when you are only locking exactly one mutex. I feel it shows clearer intent, and also you get a compiler error if you forget to give it the mutex. You don't get that with scoped lock as no mutex is a valid initialisation. Would love to know if there are any downsides to this approach. #clion
Eventually, I hope tooling like clang-tidy would warn on explicit zero-argument scoped_lock, but for now I think it's perfectly reasonable to continue using lock_guard to avoid this potential (and reasonable) human error.
Manual flushing expresses intent much better than endl anyway. Sometimes you want to flush (ex. when you're writing a logger or test where the app could terminate after the write but before the stream is destroyed/auto-flushed). Thanks for the video ☺️ #clion
Been really enjoying your videos, especially your recent dive into an assortment of C++ topics. I ended up purchasing the book Effective Modern C++ because of your video outlining nooby C++ habits, most of which were applicable to my traditional "C style"
approach to programming in C++.
About a quarter of the way through the book, and learning a bunch. Thanks!
#clion
Awesome, great initiative and best of luck with your reading! Feel free to join the discord and ask questions any time :)
Amazing vid man! That syncstream is awesome, I can never keep up with the new features.
In most c++ implementations, streams are already thread safe. The reason this example creates garbage output is because of how the output is generated with multiple calls to operator
True! cout, cin, etc... are required by the standard to be thread-safe (unless sync_with_stdio(false) is used), and most implementations implement file streams in a thread-safe way, even though thread-safety is only a requirement (by the standard) for cout, cin, etc... but not file streams, so indeed a local stringstream is a decent solution. For user-defined ostreams, of course all bets are off with this approach, and I bet that stringstream itself is not thread-safe (case when ostream passed is a stringstream) , so I would still recommend one of the methods in the video for that reason. I would also say that if you are using C++20 and taking the osyncstream approach, the code looks very similar to your stringstream approach and doesn't require the os
Awesome video as always!
07:21
1. a batch writing (every 1000 lines) is a risk to loose a batch
2. isn't synchronized queue will do the same with a mutex under the hood?
Thanks!
1. Potentially yes, more in the situation of a long lived process that writes infrequently. Handling failed writes is a much more complex topic that has a few decent solutions depending on the situation. Although, a common theme of the solutions is actually point 2!
2. Yes under the hood there will still need to be synchronization, but this centralizes the place where writing happens, making it easier to attempt to handle things like failed writes. It is more of an organizational construct to help keep your architecture clean.
0:26 wouldn't the compiler be able to optimize that second call out? #clion
Two writes is different observable behavior than one write, so no, not if your compiler is correct.
probably not, would be weird to concat two string literals into one.
There is a potential the compiler could avoid the machinery of calling a function (although neither clang nor gcc does in this case, see godbolt.org/z/cqEnP1Whs ), however, the compiler cannot optimize away a flush due to it's nature of causing a side-effect.
Your C++ content is really great! I'm learning a lot even from these shorter videos. Do you plan on continuing with more C++ content?
this was great! as a TA for a data structures course, I've always taught the use of std::endl; knowing it flushes the buffer but not considering the impact on large-scale performance. I'll make sure to integrate use of
now. The multithreading examples were fascinating. thank you! #clion
By default std::cout is thread-safe, in that a single call to operator
Yes this is good to keep in mind. Funnily enough, the core guideline right before "avoid endl" is "SL.io.10: Unless you use printf-family functions call ios_base::sync_with_stdio(false)" ( isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#slio10-unless-you-use-printf-family-functions-call-ios_basesync_with_stdiofalse ). So it is actually recommended to give up the atomicity of std::cout for performance reasons. But, if you are aware of the atomicity guarantee and are mindfully depending on it, then I wouldn't necessarily be opposed. Thanks for mentioning!
@L. Kärkkäinen why use std::flush in combination with the single writes?
@L. Kärkkäinen Funny enough, for this exact reason std::cerr flushes *everything* immediately, so you effectively still don't need any flush/endl at all. For regular logging use std::clog which also prints to stderr but does not flush automatically.
It's been a while since I used C++, but I think a *single* call to operator
The single call being safe is actually true! But only for std::cout and the like. This is not guaranteed for arbitrary ostreams, such as file streams. Under the hood osyncstream typically uses a mutex.
I was wondering why everyone added #clion in their comments, and then I read the description of the video...
I saw where that myth was comming, but I enjoyed all the video from start to end.
As someone who used C++ heavily when C++11 was still a new thing, I was curious to know how is the standard about multithreading today.
Thank you for your content, mCoding!
Do you have any plan of making videos on opengl or similar topics ? #clion
So I'm curious, what is std::endl used for then? I'm not too familiar with C++, but I always just assumed it was a way to get the system dependent line separator (containing a carriage return on some systems). If there's no legitimate use for it, can it be deprecated?? #clion
I wasn’t sure if it could help or not, because I didn’t know if some of the relevant buffers were thread-local, but I knew enough to not trust it completely.
Also I’ve wanted to try #clion for a while.
What's the syntax with the curly braces called? Like in `std::ofstream file{"out.txt"}` what are the curly braces doing? I'm somewhat used to c++ through Qt, but I don't think I've seen this syntax before
I really appreciate the "thanks
" cout
Hey James! Im currently a high school senior and very advanced in Python. I would like to learn C++ but don't really know where to start. I know the basics (pretty much C) but modern C++ is a little too much for once. Do you know a great ressource where I can learn it?
Hi there! I would reccomend finding an online free pdf of "The c++ programming language" by barne stroustrup. You should be able to get one for c++11 free online, don't forget earlier then c++11.
What about the legendary classics like C++08?
Just starting with C++ and really like to watch these videos to get some deeper understanding. Thanks a lot #clion
Another great video James. Did you consider making a c++ course? Or is there an existing one that you'd recommend? #clion
I don't have one. Start by watching all of C++ Weekly with Jason Turner!
It would be nice to know: is there any scenario where endl is needed or preferred? #clion
Thanks for explaining
and std::endl in depth, it was indeed virtually impossible to find an explanation I’d understand/believe until now.
I’d also love to use #clion on my Mac. I’m not into text editors for C++ in MacOS.
Very interesting! I hope to see more multithreading content in the future =)
thanks for your videos. do you think you could do some videos on programming enviroments? text editor + compiler + debugger + build system + meta build system? #clion
Great stuff as always! As a primarily C developer, I always enjoy learning about the features in C++ that I should be using but never know about, keep up the good work! #clion
It's nice that you have expanded your topics to include c++ #clion
your videos have absolute priority. ill stop whatever i do when a video of yours pops up. #clion
Great to hear! Thanks so much for your support!
Being fluent with C++98, post C++11 code looks exotic to me #clion
Ok then. Why we have std::endl in C++, if it's usage is discouraged? Isn't that weird that at the first glance simple end-of-line constant turned out to be flushing operation? What's the original purpose in that? #clion
As is the case with many things in C++, it was chosen long long ago before the implications were fully understood and at a time where the constraints of the hardware were very different from what they are today. And, for backwards compatibility, it cannot be changed, ever.
I miss your C++ videos!
Well thank you, maybe another one coming soon!
@@mCoding That's great! :D
Amazed by your videos
Thank you!
I'm really glad that you've been making a lot more C++ content lately, as your Python videos were already top-notch, and this kind of deeper approach is especially useful with a language as versatile as C++. You don't just explain why something should be avoided or doesn't work, but you always offer multiple solutions as well. Thank you! 😄#clion
Could you fix the problem by first creating the line you want to print as a string and only doing one
Indeed, std::cout has special wording in the standard that actually guarantees that this would work, see en.cppreference.com/w/cpp/io/cout for a brief explanation. Of course, if you are writing to a file you're out of luck!
#clion is enough?
for this short example, I would build the string then write into Ostrem as a whole so that competition would not alter the inner order of every single line #clion
What ide and theme are you using?
Clion and Monokai Pro!
what color scheme is this?
What's the point of std::endl then?
Suppose you want to display a line of information to the user immediately, you don't want to wait until a buffer fills to display it (perhaps printing this info is rare and it would take a while to fill), you want to display NOW. Then you should use endl because you intend to flush. This is mostly unnecessary since cout is usually line-buffered anyway, but it doesn't _have_ to be line-buffered. Also, whether or not cout is already line-buffered, using endl signals to readers of your code that you _intend_ to flush immediately.
I liked the different C++ version comparisons.
I am using C++ 17 and only used lock guards because I didn't know better
#clion
Nice overview and explanation on how to do this in different versions of C++ as well + subbed! #clion
i wish i knew about ossyncstream earlier, actually super helpful
Glad i could help!
Now I have to ctrl-F "
At least you use "std::endl" instead of just "endl"! Much easier to search for :)
@@mCoding I've learnt from the best!
Hope a second reply will still notify you! You get a CLion! Email me to claim (find on my about me).
@@mCoding Oh wow! Thanks
To round off this saga, there were 92 lines to change!
What Code Editor & Theme Are You Using ???
CLion and Molokai Pro theme
Though it's not the main the point of the video, I actually ended up learning a lot more about multithreaded programming in general than I did before. Thank you.
#clion
This brings some great memories, i moved away from c++ (yes yes, heresy) but every time I see your videos it makes me want to get back :) #clion for the win :D
Use whichever language is most useful for whatever you are working on. I have no ill feelings of other languages.
Cool informative video, don't know that endl kill productivity. Thanks #clion and mCoding
Nice Video! Definitely need to re-watch 🙂
Thanks for your stellar videos. Home sick bc the holidays, and your videos are helpful both in coding and helping me get passed my rut. Thanks again.
Also, #clion
Get well soon!
Thank you for adding previous C++ Version. I'd like to see more 'Myths' #clion
Are we still on it? #clion
Already knew that but still, the delivery of your content is great! #clion
Love it! C++ really isn't as hard as people made it out to be when I first started, and videos like this really help me getting more and more into programming
#clion
I've only begun to dabble in c++, but am learning lots from your channel, including python. #clion
i hate visual studio code cuz it sometimes doesn't compile changes i make #clion
Now I should tell my teacher to correct his “Introduction to C++” manual ;). #clion
Well, for a teacher I can understand that what you teach your students doesn't necessarily focus on best practices. Sometimes it's not worth it to explain a best practice if the benefit is not core to the lesson and would take a lot of time. Hopefully your teacher is already on board, or feel free to send them this video :)
"Side effets are bad."
Everything added to the standar since 2000 has a host of side effects.
Jesus take the wheel.
Awesome content! Also really cool to see Jetbrains do a giveaway, especially for #clion
Interesting comparison of endline, use cases and nice touch with solutions in different c++ version #clion
Giving solution for different C++ version was superb, thanks for the great video #clion
Can't we use std::format in C++20? #CLion
Yes! But I'm itching for better compiler support before recommending it yet. I will make a video about it once the major compilers all have it working in a stable version that most of my viewers would be able to upgrade to easily.
I love your channel, even if something I watch never impacts my life I just love the in-depth explanations you give for everything #clion
Thanks so much! Glad you enjoy!
Hope this reply gets to you! You get a CLion! Email me to claim (find on my about me).
Awesome, would be nice to see more videos about multithreaded code in c++. #clion
i don't even write C++ (more of a kotlin/java and python guy) but i appreciate these videos anyway. thanks for randomly choosing me to have #clion by the way, really appreciate it
Great video. Honestly didn’t even know the C++11 solution was that compact! #clion
I always liked c++ since it was my first programming language but I did not go deep with it. Your videos are really helpful for me to learn more. #clion
I always assumed it used the system's line ending character
or
. Good to know I've been doing it wrong and how to do it correctly! #clion
Yes this is a common misconception, endl is
even on windows where you might expect it to mean CR LF.
TH-cam gang
My solution to this is const std::string endl="
"; at the start of my program and pretend to use std::endl to confuse everyone. #clion
Chaotic good, I see.
great video! i'm very very new to multithreading and threads overall and this video was very helpful, thanks :D #clion
#clion could be a nice tool to learn C++
Nice video, quite interesting.
I believe std::endl should portably allow Windows carriage return line feed pattern. Also auto flush on newline is a common feature of various buffered OS objects like stdout or stderr. Therefore flushing is sometimes automatic and unavoidable. As for thread safety of the OS write and read calls, likely they are thread safe. So all the C++ nonsense here though useful is far from the only perspective on the issue. He left out the C and raw OS library perspective.
std::endl does not produce a carriage return on Windows. It produces a newline then flushes on all platforms, as required by the standard. While auto flush on newline may happen for certain stream, it does not happen for all of them, especially not file or string streams, and in these cases endl is often a common and significant performance slowdown. The advice to avoid endl is not my personal vendetta, it is time tested battle proven advice even recommended in the C++ core guidelines maintained by Bjarne, creator of C++: isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rio-endl. I don't talk about C in this video because this is a C++ video about a specific misconception about std::endl, not a how to guide for printing across different languages. C is a different language than C++ and it does not have std::endl.
@mCoding in Java the System.LineSeparator does give a OS specific newline. Didnt know C++ standardized the Linux variant. Interesting reference thanks! Indeed the lower level stuff is another topic. But one which although you understand, many don't.
Great video, really informative and useful, i might not have understood 1/2 of the things you said, but someday tomorrow i will!
#clion
My idea as I was watching was to make a string with the line including the
, then
Thanks IntelliJ for the nice IDE's #clion
I recently worked on some distributed computing code in which I found out this myth was totally false, thankfully it only really needed to return data at the end of the process. So I flushed all the debug and printing info into a string stream printed them from the managing thread. #clion
Nice, thanks for all the different solutions! #clion
And I remember the professor that teached me C++ say to always use std::endl because "it's the c++ way"... #clion
Teaching is hard, sometimes professors say things that are good approximations for learners or are otherwise helpful simplications for the classroom allowing them to skip longer explanations and allow the class to spend precious time on more important topics. Since the biggest difference is worse performance using endl, I can understand that a beginner class (the kind where you would be learning what endl is) would not be concerned much with performance, so it would be simpler to just tell you to use endl and move on.
Such a difference in C++ 20 implementations robustness #clion
Great video as always! Keep that great work! #clion
You get a CLion! Email me to claim (find on my about me).
@@mCoding Here you go: 71
Excellent
I'll add my two cents. #clion
I did not know that endl was a bad practice. Thanks! #clion
So lucky! You get a CLion! Email me to claim (find on my about me).
@@mCoding 18 is the answer. Best regards Mert.
C++ scares me, but I guess I could give it a try if I get #clion 😳
#clion I use vs code
gold!
Didn't know about jthread in c++20. #clion
#clion once again a grait video, thx :)
Great stuff #Clion
Amazing 😍😄 love 💕 from Pakistan
#clion the new lion in town
Great video! #clion
hmm interesting thanks #clion
#clion helpful vid
bazinga #clion