Interested in advertising on Derpibooru? Click here for information!
Help fund the $15 daily operational cost of Derpibooru - support us financially!
Description
A slide from the lectures on C____ Toolchain held in Moscow Institute of Physics and Technology (MIPT / PhysTech) for Department of Radio Engineering and Cybernetics (DREC) students on ~4th year (2017). Link to repository with lectures (different C____ related topics, in Russian): https://sourceforge.net/projects/cpp-lects-rus/
It was really unexpected to see ponies on the slides of the lecture… There’re some more ponies! Is it a reason why I started to properly learn C____ two years ago? :)
Translation >>
Title: “Working with GDB”
Twi says: “It’s time for debugging…”
It was really unexpected to see ponies on the slides of the lecture… There’re some more ponies! Is it a reason why I started to properly learn C____ two years ago? :)
Translation >>
Title: “Working with GDB”
Twi says: “It’s time for debugging…”
>implying there is anything wrong with ANSI C
Also C > C____ anytime
If an object can avoid being default constructed it should be. Very few objects I make ever have default constructors for this reason (it’s not needed since again it adds overhead to put it in a non-invalid default state to be “safe”). Also your example is still less than ideal imo for various reasons. Firstly,
a
andb
can clearly beconst
but they miss out on that because they’re not being initialized with the data you’re setting them to directly (a
is being modified but that should be a for loop anyways to avoid bug prone logic with something as simple as trying to loop for a number of iterations, but really that is more opinion based since a while loop might be your own preference). Additionally,d
can and should beconst
and be located in the inner scope for reasons previously mentioned. Const correctness is there to help the program be safer, right now one could accidentally write to any of those variables where in the original intent they were assumed to be constant throughout (after all, these are inputs, they don’t appear to need to change at any point), and discontinuities between the programmer’s mind and reality are what cause bugs.Personally I’d write it like:
unsigned const a{ input(“a”) };
unsigned const b{ input(“b”) };
unsigned c{ 1 };
unsigned const d{ i * b };
}
Your point about temporary objects is valid, constructing expensive objects inside of loops usually isn’t a good idea, but neither is assigning them. Remember, copy and move assignment both call a destructor of the old value just the same as it going out of scope or to the next loop iteration, and a constructor will still need to be invoked in the loop body somewhere each iteration since you aren’t just whipping up classes out of thin air so it’s really no different than if it was initialized as a local instance within the loop scope. In cases like that you may want to redesign your code so that it does not happen, but for integers or other primitive types you won’t have issues since they’ll be in registers and heavily optimized anyways, the location in scopes and const-ness of them is really just benefiting you for the most part at that point (and perhaps helping the compiler optimize a little better).
Edited
I did not know that, C____ is not really my home. That’s definitely cleaner.
@LemonDrop
I didn’t mean “I like to declare variables wildly out of scope for no reason”. I wasn’t very clear though.
I did specifically mean declare, not initialise. I don’t think it should even be possible to instantiate a well-designed class to an invalid state, its constructor should prevent you doing that. I think we agree that invalid-by-default objects are a bad idea.
I didn’t say “all my declarations go at the top”, I just said “away from functionality if possible”. I meant that something like this seems fairly reasonable:
Because it keeps the logic slightly cleaner and no objects are involved anyway.
Delaying object creation is obviously good but sometimes it’s more readable to make them a little early. A little.
My other point was that if you have a type declaration inside a loop then implicitly you’re doing at least an assignment there: something’s getting written to memory on each iteration. Sometimes it can’t be avoided but when possible I’d rather not be creating temporary objects inside a loop if I could make one object earlier and use it multiple times, even when they’re only actually needed inside the loop. Maybe that’s more applicable to garbage collected languages than C____.
Dang the edit window expired, I just remembered another reason why it’d bad too. With initialization you can actually construct
const
variables, but if you declare everything at the top always you eliminate the ability to use const anyways since you must assign to it at some point to use it, which effectively removes all the safety const could add to a good chunk of your program (it can still be used in parameters and whatnot, but safety in modification of variables within scopes is always an nice thing to have).Edited
Again that is bad practice in C____ due to the performance problems it can cause with more complex objects. The compiler cannot magically defer initializations if they’re complex enough at times since they may have potential side effects, so yeah it’s just always good to only initialize things when you absolutely need to, not at the very top. Furthermore it promotes leaving variables in an uninitialized state (which is more bug-prone), or even worse, a default constructed state if it is an actual class rather than a primitive type (overhead which could be avoided assuming the class even has a default constructor to begin with), not to mention force the what should be initialization to be a copy or move assignment (which will destruct the previously default constructed object and waste even more time). If anything too, the fact that this was an explicit design decision in C____‘s creation should be hint enough on what the good way to do it is, since they knew it’d be a problem with how C did it at the time and changed it, which C99 promptly took back from C++98.
Additionally style wise I dislike putting everything at the top since within the context of a potentially hundred line long function you forget what those variables’ types are easier and stuff like that, creating an absolutely huge monster mess at very top which isn’t useful to anyone either when refactoring code rather than just finding things near where they are used. Sometimes in rare cases too you may end up with conflicting variable names if two things should be named the same for whatever reason, and keeping things more local to scopes would have a higher chance of avoiding such an issue. Finally if you’re not using initialization and preferring assignment, you miss out on features such as list-initialization which allows for additional checking and uniform syntax of class and primitive type initialization of all kinds, which I personally use everywhere.
Tl;dr, don’t do it. C and C____ even more strongly are all about scopes, if we didn’t care for them then we’d not just only put all our variables at the top of functions but just make everything global and put it in 1 file for easy access. Limiting scope of information makes programming easier for the programmer, more performant and introduces potential optimizations more clearly for the compiler.
@Background Pony #E8A7
That’s good, but it just bothers me that they’d choose that style of declaring variables when in C____ it shouldn’t make any difference for debugging purposes either way. I’d argue even the method of deferring initialization in this case would make debugging easier as the variables listed for debugging in a step by step view would only be those who are actually relevant to the current scope depth that is being inspected rather than having them all thrown on you at once.
Edited
It wasn’t a “good C____ code example”, but “something C-like that should be debugged”, it was a lecture on Toolchain.
There is the next course (available in repo, link in description), called “Generic programming”… It’s about templated library C____ programming using C__+17 and even touching C__+20 proposals. If you want modern :)
std::swap
is a thing that exists.I don’t actually code in statically typed languages often; when I do I like to keep type declarations away from the actual functional code if I can and outside of loops if possible. I guess the compiler will produce the same output but I’m never that sure. Initialising counter variables outside of their respective for loops is just bizarre though – I guess it saves typing “int” a couple of times but if that’s the primary concern the author needs to re-think their priorities.
What I really hated most was the kludgy use of an int for a flag and the bad variable names. I’d have a couple more whitespace separating lines too if I could but I had to fight with the forum formatting system to even have proper indentation.
Indeed, I sometimes see questions on SO like asking about how to use the Turbo C____ compiler and all that from back then too and it’s like lol did the DOS-era IDE display give you any concerns at any point about if the technology you’re using is up to date.
I think it really depends on teachers and stuff though, from what I’ve seen schools always have their stuff a bit out of date but not that far, and even then the instructors are usually aware of the newer stuff and are just teaching it the “simple” way to make it easy to learn. What I can’t get about this image is that there was never any requirement in C____ to put variables at the top of the scope like that, and despite the argument which could say it’s stylistic, it’s objectively bad in in C____‘s case due to the potential to defer potentially costly construction of more complex types until later in a scope (and potentially avoid it if it’s not reached if control flow does not reach that). So really it’s just like someone wrote this course info with their mind still stuck on C89 (C99 copied C____ and allowed for you to place variables more freely) and just called it C____ or something, which is just odd to me lol.
Schools are very slow to update their materials. Some places are probably still teaching “C____” using that utterly ancient Borland C____ 5 from 1996.
size_t length = numbers.size() - 1;
if (length < 1)
return; // don’t try to sort lists of 0 or 1 numbers
bool sorted;
int temp;
do {
sorted = true;
for (size_t i=0; i < length; ++i) {
if (numbers[i] > numbers[i+1]) {
// swap them
temp = numbers[i];
numbers[i] = numbers[i+1];
numbers[i+1] = temp;
sorted = false;
}
}
} while (!sorted);
}@
Edited because: Formatting fix.