C++ Questions

Pages: 1... 45678... 13
We can already do that using the following syntax:
1
2
3
4
5
6
7
8
{
	int i {};
	do {
		cout << "Num to find: ";
		cin >> i;

	} while ((ms1.count(i) == 0) && (cout << i << " NOT FOUND TRY AGAIN...\n"));
}
yes - but now you have to have an extra set of braces which shouldn't be needed.
“Shouldn’t” ? According to what metric?

The braces explicitly create a lexical context. It is exactly what they are for. It has been that way since the very old days of pre-standard C. I use them for this purpose all the time.
You can define a variable as part of a for, if and switch statements. So why not a do statement?
Being late to the conversation, I recognize my ignorance and that in this specific context there certainly could be syntax to do it. Peter87 already pointed us in the right direction.

Suggest a syntax. Implement a patch, ’cause no one else is likely to want to bother, and see if it doesn’t get accepted into the standard. You’re looking at some serious, long term stuff here, jsyk.

I personally think that it would be useful for a do..while to have the scope of the while condition extended to include the body of the do. But I haven’t found any truly compelling reason to do so, nor have I investigated whether that will break any extant code.

Simplest, perhaps, is the other way around similar to what SubZeroWins suggested (now that I am bothered to go back and read it)? Doing so reads out of order, though, which I dislike even in class/struct definitions (you know, when people’s inline methods refer to private stuff declared further down in the listing).
Last edited on
Peter87 wrote:
SubZeroWins wrote:
"The while() bool check, although is part of the loop, is considered to be outside the block code...and there is no inference the compiler has to include it as part to the block...that part is understood!
They could have programmed this alternatively though, but there is no logical reason to reset a declared variable inside the loop and so it was forced to be declared outside."

There is nothing nonsensical about declaring variables inside loops. You just need to know the lifetime rules of local variable and realize it will get created and destroyed on each iteration. If that is not what you want then you need to write it some other way.


Here, I was referring to not just any variable created in the do block body, but if they had alternatively made the do/while() bool test variable, "i" in my example, specifically able to be created WITHIN the block. I was inarticulately trying to suggest that I understood that the committee had made the right decision and I understood why. Otherwise, if the bool was able to be created WITHIN the block, then this would be illogical and nonsensical, because the var would continuously reset itself unnecessarily (100, 1000, 1 mill ...n times loop count)...why do this when you can create and initialize it only ONCE OUTSIDE the loop. So all that is understood.

Alternatively, in this theoretical creation, if there was a way to tell the compiler create this variable ONLY ONCE internally, then even better...in this instance I was thinking in terms of the for() loop, which creates and initializes the bool variable ONLY ONCE!!!! So I don't know, maybe we can do it with a theoretical do/while() too?

Thanks for the link Peter, but I don't have enough experience to make such a proposal.

mbozzi
That while(true) IS a tempting alternative and it looks very clean thank you.


Duthomhas & mbozzi
I will have to concede that I don't know enough about the inner workings, but that I would love if such/similar syntax was create for a do loop. Each time I used this I found myself saying surely there must be a way to already do that and that I cannot believe there wasn't. Once again, no big deal, but it itched me enough to post about it and garnish your opinions...which I value.

There would be other smaller bonuses too:
1) You can include such things as a cout that you did not want to include on the very FIRST default loop through, only the 2nd time and thereafter.

2) Variable declaration & initialization can take place as part of the syntax (done before loop starts), just like a for loop or alternatively MOVED to before the do loop start.

3) The bool test variable ("i") would be deleted after the scope and last bool test, and memory will be relinquished. If one needed a lasting var, then omit the internal one and declare one before the do().

4) Syntax follows a for() loop and is recognizable.

1
2
3
4
5
6
do
	{
		cout << "Num to find: ";
		cin >> i;

	} while (int i = 0;  ms1.count(i) == 0; cout << i << " NOT FOUND TRY AGAIN..." << endl);

SubZeroWins wrote:
Otherwise, if the bool was able to be created WITHIN the block, then this would be illogical and nonsensical, because the var would continuously reset itself unnecessarily (100, 1000, 1 mill ...n times loop count)...why do this when you can create and initialize it only ONCE OUTSIDE the loop.

This is a non-issue for simple types like bool and int, or even simple structs, because they are cheap to create.

And when I say cheap I mean it's likely to cost you nothing at all. Primitive types and classes with trivial constructor and destructor should be "free" to create and destroy (compilers normally reuses the same memory location on each iteration). What will cost you is if you initialize/assign the variable each time but if you do that anyway then there is no overhead.

If the type was std::string it might very well be more efficient to declare it outside the loop (mainly because it can reuse the same capacity and doesn't have to allocate new dynamic memory each time) but in this particular program the slow part that is going to dominate is likely the IO (cout and cin).

Obviously, if you need to use the value from the previous iteration on the next iteration then you have to declare it outside the loop (or use a for loop).

SubZeroWins wrote:
in this instance I was thinking in terms of the for() loop

The for loop is technically unnecessary but it's for a very common use case. You want to loop from some value up to some other value, and you can choose the step size but often it's going to be 1 so you use ++.

 
for (int i = 0; i < n; ++i)

This sort of loop might be falling out of fashion but this is what you used to do whenever you wanted to loop over any array/vector.

It also reads pretty naturally:

"for each integer i from 0 up to n..."

The ordinary do-while loop also reads easily:

1
2
3
do {
	something();
} while (n < 10);

"do something while n is less than 10.

I don't think your proposed do-while loop reads as easily and it's also a much more niche use case so I'm not convinced it needs a special syntax. Adding syntax to the language is not "free". It requires everyone to learn that syntax and it increases mental overhead.
Last edited on
The problem I am having with this is that our example is fundamentally broken code — as such it is not something that demonstrates any actual need for an update to the language.

For starters:

  • The variable i is local to the loop, and consequently not available after! (What was the point of obtaining a value, then?)

  • Input is not properly obtained. (Using >> for user input is Always Wrong™. I’ve written countless posts here about it.)

  • Looping for the user to input correctly is the Wrong Thing To Do™. I touched on this already. Either input succeeds and the program moves on or it should fail, notify the user, and go back to the prior menu/input wait state/whatever.

  • The loop fails to terminate if user input is bad for multiple reasons. (See also point #2.)

  • The loop lacks basic entry checks, but I will generously waive this as “done already and not topic of conversation about loop syntax”, even though I don’t perceive it to have been considered. (For example, what if ms1 contains no i that the user can input?)

User input is, frankly and quite seriously, one of the more difficult things to get right. I could design an entire university-level course on it. Somehow, however, it is never quite properly addressed — not in any textbook or online resource or college course I have ever seen or heard of. Somehow it is one of those things always assumed to be obvious, but it is anything but obvious...

Consequently we get untold collections of people online asking questions about how to fix things like cin >> i. You fix it by never doing it like that.


Were I to write a simple program desiring input of some known number, it would look one of two ways.

(1) standard sequential “do this then that and so on” kind of programs:

1
2
3
4
auto i = ask_integer( "Enter the number you know I know about that you want me to do something with: " );
if (!i) throw error( "That wasn't a number." );
if (!ms1.count(*i)) throw error( "I don't know anything about that number." );
do_something_with_the_integer( *i );

(2) stateful kind of program, like stuff that has menus to do things, etc

1
2
3
4
5
6
7
void my_menu_function()
{
  auto i = ask_integer( "Gimme the int you wanna use to do stuff with yer data: " );
  if (!i) return message( "That weren't no number." );
  if (!ms1.count(*i)) return message( *i, " not found!" );
  do_something_with_the_integer( *i );
}

Both of those examples obviously make use of constructs that require additional programming elsewhere, like the ask_integer() function.

1
2
3
4
5
6
7
8
std::optional <int>
ask_integer( const std::string & prompt )
{
  std::cout << prompt;
  std::string s;
  getline( std::cin, s );
  return string_to <int> ( s );
}

Heck, you could make that even nicer by making it a templated function. This would give the compiler options to truly optimize it and give you a smaller binary.

1
2
3
4
5
6
7
8
9
template <typename T>
std::optional <T>
ask_input( const std::string & prompt )
{
  std::cout << prompt;
  std::string s;
  getline( std::cin, s );
  return string_to <T> ( s );
}

And for the sake of completeness, here is the most basic version of that “try to get a T out of whatever the user typed” function, all encapsulated in its own little function nice and pretty-like:

1
2
3
4
5
6
7
8
9
template <typename T>
auto string_to( const std::string & s )
{
  T value;
  std::istringstream ss( s );
  return ((ss >> value) and (ss >> std::ws).eof())
    ? value
    : std::optional <T> { };
}
Looks simple, don’t it? Looks can sure be deceiving.

In any case, we again find that life is made simpler by a utility functions that help us out.

But we also find that there is no free lunch. If you want pretty one-liners, you’ve got to do something somewhere else to make that happen. And that is a fundamental truth to all programming and programming languages!
It stands out in C and C++ because they are both significantly more low-level than something like, say, Python. Modern C++ gives us some powerful tools in the Standard Library, like the Ranges library, but the reality is that anywhere you see pretty it is because there is a lot of very carefully crafted code behind the scenes making that happen.

And we, as programmers, have to play both sides of that. We create something, a class, or a command-line program, that presents a nice interface to some user —whether it be another programmer or some five-year-old kid standing on the chair so he can reach the Enter key— but we spend our time on the behind-the-scenes that the user never sees.


Anyway, my point was that I think it is a mistake to focus on the language design when we have yet to find an example that clearly demonstrates a good reason to improve it. It is okay —and a Good Thing™— to want to make our own tools nicer and prettier. Just get the rounds properly chambered before you start lining up the ducks.


$0.03
User input is, frankly and quite seriously, one of the more difficult things to get right.


Absolutely. Over the years I must have (re)written several routines to perform this. Input is based upon streams and there is no differentiation from input from a console stream and input from a file stream. Standard input can be re-directed to come from a file so you can't really have a different way of console input from file input unless your console program will only ever work with keyboard input.

What would be useful, IMO, is a C++ standard way of obtaining validated console input as I agree with Duthomhas above in that this is never quite properly addressed in books etc.
Gobs of proper C++ ways to code are not well addressed in books or with online tutorials, some aspects are totally ignored.

Many books are apparently rooted in teaching C++ as if it were C and only later and briefly explain C++ features. For instance: regular array/C strings before std::vector & std::string. (Lookin' at you, Sams books....)

User input done right and proper is a complicated and very advanced subject, sadly. The slap-dash methods too many book and online tutorials deal with it leaves a lot to be desired. Never bothering to show better ways to build an input routine.

One IMO good online example of "C++ Console User Input Done Right":

http://lb-stuff.com/user-input

The example bits of code are old, I don't know who wrote them or the blog page. Going template could be a nice update.

There's a link on that page for a very easy and simple tokenizing method for parsing out multiple inputs.

https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string/237280#237280
L B is one of our very own long-term forum members
https://cplusplus.com/user/LB/

He wrote that page a while ago because he got tired of answering the same old questions over and over (and over).

Haven’t seen him in a while tho.
We miss you, L B!
Peter87
Understood, thank you.

Duthomhas
Yes, user input can get complicated and hairy depending what one needs done. This was not about a complete program, just the smallest snippet to show the request. The actual code did nothing more than search if the value "i" was in a multiset. I do understand that user input needs some well thought out error checking though. As we know these control statements and iterators can do a million things and the contents were not a specific concern at the moment, only the instantiation/initialization of the variable doing the do bool check, iteration, and a way to introduce an additional statement past the very first loop.

I understand your sentiments, thank you!

A user input course or book would be spectacular, please someone do it with good lessons.

George, I took a look at the link briefly, but I will go through it with more detail. Thanks!
I see it's coming up on 6 years when L B was last seen here. I probably got the link from him or someone else before L B disappeared.

My "join date" is a bit off since my original account was 'hacked' and then deleted by someone who thought it was "a joke" to do so from my PC.

With 'friends' like that who needs enemies.
I think I have vague memories of this. The ‘friends’ used your account to make a few obnoxious posts before you shut that down, IIRC.
 
for (int i = 0; i < 10; ++i)


From what you have all told me you can't just make the compiler do anything you want, it has to be done in a certain way with certain parameters.

So, what does the for loop rewrite look like, something close to what I have below? Is the for() syntax above rewritten in assembly to resemble something similar to below and loops through the if's while condition is true?

1
2
3
4
5
6
7
8
9
10
	{
		int i = 0;
		{
			if (i < 10)
			{
				//for() body...do whatever
			}
			++i;
		}
	}


or this, the latter of which makes even more sense, although with the whirlwind I've seen here I don't know if the compiler can do it.

1
2
3
4
5
6
7
8
	{
		int i = 0;
		if (i < 10)
		{
			//for() body...do whatever
			++i;
		}
	}
Last edited on
Yup, that was what happened. After making the very obnoxious posts the 'friend' deleted my account. I called the police to get him removed from the premises. He left while I was on the phone and for some strange reason I have never seen or heard from him again. Go figure.

I guess we both aren't going too senile after all. :Þ
@SubZeroWins
It is easy to get bogged in syntax and forget the larger picture.

What exactly are you trying to do? If you can explain it from the user’s perspective, both correct and error interactions, all the better.

Then we can suggest a straightforward and efficient way or two to do it.
I am not trying to do anything with it per se, just trying to understand how the compiler will handle the default for() syntax organization and structuring.

 
for (int i = 0; i < 10; ++i)


Will it rewrite it as such for ease of assembly processing, because it cannot handle it in this immediate and direct syntax and it has to organize it line-by-line for assembly processing.

So will the re-arrangement look more like my example or what will it look like exactly? Is that a good representation on how the c++ code will look like translated to assembly on a line-by-line basis?

In other words, the compiler can't directly deal with this immediate syntax and it has to process it on a line-by-line basis.

So first, it creates the body of the for() iterator and the variable i (so that when it's done the var i and body gets destroyed):
1:
1
2
3
4
{
	int i = 0;

}


Then it creates the if() condition:
2:
1
2
3
4
5
6
7
{
	int i = 0;
	if (i < 10)
	{
		//for() body...do whatever
	}
}


...then the increment (++i), then the loop through the if() statements..etc.
Last edited on
If you really want to know, sign up for a course on compiler construction.

Low level bytecode or machine instructions are very much simpler building blocks, and do not make much sense to describe in terms of C or C++.

For example, the i variable may not exist as an actual int value stored anywhere. It might not even exist in a machine register.

There is no such thing as “line-by-line” at any level past tokenization of the C++ source code file. After that it gets transformed into an AST — abstract syntax tree — over which various optimizations and simplifications are applied, after which it is transformed to relocatable machine code (in an object file), which the linker combines to produce your executable.

It’s a relatively straightforward, iterative process, but not the least bit trivial.


What you should be getting out of this is that the final machine code that the “compiler” generates is not the same thing as the high-level language design itself. When using C++ (or C), it is typically a mistake to start thinking of it in terms of what assembly/low-level output it will transform into.

You should instead be thinking about your program’s structure in terms of the C++ language itself.
Pages: 1... 45678... 13