C++ Review Questions

Pages: 1234... 10
I think those types of Udemy/Youtube intro and even intermediate videos are too simplistic now. Even college intro courses will not cover this material that you guys are exposing me to.


videos, unless the visible part being shown is critical, are usually the worst form of teaching. If you want to know how to take apart an engine, sure, a video is great. Or even learning a trick with your IDE, fine. But actual code writing, the video brings nothing: its a talking head or typed code onscreen. The majority of those teaching videos are 2 min of "my name is" at the front and 2 min of "check out the rest of the series and all my other crap for $19.95" at the end, with 5 min in the middle of about 1 paragraph worth of information.
I recommend you hit up text sites where you can dig in and read, getting as much as 3 to 5 times the info in the same time spent as video (where the medium requires speaking slowly and the ADD generation require repeating the same idea 3 ways).

College is not teaching you to program. College is teaching you how to teach yourself to program by giving you the basics and showing you how to research (eg look up syntax online) details, how to develop an algorithm (eg numerical methods class, algorithms class, etc) or look one up online (a study of sorting perhaps?) and so on. When you get out, you should be able to assemble what you need to do your job, and you will get help at the job from your more experienced coworkers.

Anyway, for detailed answers, finding the material online becomes more and more difficult. The best thing you can do if you want to dig deep is take a couple of days to brush up on your search engine skills, which many take for granted because the default is good enough for simple questions, but finding the one or two pages that answer exactly what you want takes a little more voodoo and practice. And some info just isnt out there... the majority of programmers don't run into the deep stuff very often. I doubt I could tell you 50 / 800 pages on templates: I keep mine fairly simple and rare, most of my classes are not templated as the data I deal with is rarely in flux and I don't build containers for a living.
To go along with what jonnin said, most C++ formal classroom and video instruction teaches beginners a C++ that is before C++11. Showing students how to create a custom dynamic array or string class instead of showing them how to use what the C++ standard library has to offer.

The custom constructs are not very bullet-proof, they are only useful for specific uses unlike the stdlib.

Being a self-taught programming hobbyist I have a "maybe some day" interest in how the stdlib tools are crafted, but my major emphasis is how to USE what is available. Nearly every time I thought I'd have to cruft together some quickie custom solution to a problem I found out the stdlib had already done it. Or a 3rd party library was out there. Boost, for example.

People a whole lot smarter than me did the work already. And did it so much better. :)

Each new standard adds something new. Sometimes just a twist on usage, sometimes a whole new workshop stuffed to the brim with brand new and shiny tools. C++14 for the former, C++11 and C++20 for the latter.
@George P
Thanks. When I cover modules, I am coming back to re-read your posts on modules and may have some Q's.

I loath .ixx and will probably never use it.


Ha, that is my exact sentiment... .cppm is so comforting.

@jonnin
I hear ya & I know what you mean as it is all true. But then again newbs can use those vids as a stepping stone to a good book...nothing beats the info in a good book. I watched some videos after I read half of my book & then watched a few more just now. I tell you one thing though, every now & then someone uses a part of the standard lib that I have not seen in my book though. Like you said though, problem is you have to watch too much wasteful info to get to the unknowns. Honestly, I wish one of you guys would make a nice set of videos as I would love to hear the info coming out of your mouths ...I would be glued!...don't forget to hit that like button...
Appetizer questions:

QUESTION 2)
What is meant by an "integral"? Is it any type that is stored as a whole integer number, so no floats, double & L double (the non-integrals).

Book just used literal, but did not fully explain & used the examples below. BUT I read further and find out that bool & char are considered integral types too? Bool because originally in C it was a unsigned short int. Also, char because it is an ASCII value. What about strings, sure they are classes, but they are arrays of char's..so they are probably integral too, right?

Incidentally, I read the first chap & little bit of 2nd chap of 2nd book (Beginning C++20 from Novice to Master Overtimer) and it too used "integral" when referring to integers,but did not fully explain either...maybe down the road. It was clear though that it was referring to integers, but I still had to go to outside source to see what bool & char were really considered.

So, at the end integral is all of the types, except for float, double, L double, & any type that has a fraction?

unsigned long long int for integral literal
long double for floating point literal
char, wchar_t, char16_t, and char32_t for character literal
const char* for raw string literal
const char* together with size_t for string literal

_____________________________________________
QUESTION 3)
Why is a switch-case construct limited to only integer & char? Why would they implement this limitation? You can compare if (3.14 < 3.1415) just fine, so why not for switch?
_____________________________________________
QUESTION 4)
Yes, I saw that both return the same value when first encountering them, and so I just moved on. But my C++ senses are tingling too loudly now.

https://cplusplus.com/reference/string/string/length/
"Returns the length of the string, in terms of bytes."

Now, I don't know anything about programming UTF encoding, but I know they exist and that sometimes a character can be represented as more than one byte (8 bits). So, now please tell me that.length() should really just report the length of the string (without \0), independent of the encoding, & as I really thought it should? Why have both size & length report the same? Is there ever a time when those two values will not be the same?
1
2
string1.size() 
string1.length()

_____________________________________________
QUESTION 5)
My 1st book used "size_t" and did not explain it and then I saw it used in a few places online. Find out it is just an unsigned int and sources said it is 4 bytes. I verified it was 4 at the time and one fine day all of a sudden it was 8. I was too new at the time, but thought it had something to do with certain compilers/computers allocation of memory.

Now I realize that I am on x64 PC and my debug compiler was set to x86 and when it read 8 bits it was set to x64.

"size_t is an unsigned integral type" //From link above.

But this is not true on x64, because sizeof(unsgined int) = 4 bytes there, but size_t = unsigned long long int (8 bytes).

So I guess doc should be???:
"size_t is an unsigned integral type" //For x32/x86
size_t is an unsigned long long int //For x64
2) For a 'meaning' of integral see
https://en.cppreference.com/w/cpp/types/is_integral

arithmetic also include floating point
For a list of different classifications see https://en.cppreference.com/w/cpp/header/type_traits

3) Since double values provide an exact representation only in case when the value can be expressed as a sum of powers of 2 that located "close enough" to each other (within the length of mantissa), and because switch works only with exact matches, you cannot use double in a switch.

4) .size() and .length() for string returns the same value and are interchangeable. All containers have .size() and people are used to dealing with 'length' for strings so both are provided. There is no difference. They will always return the same value.

5) std::size_t can store the maximum size of a theoretically possible object of any type (including array). For a 32 bit compile this will be 32 bits and for 64 bits it will be 64 bits. https://en.cppreference.com/w/cpp/types/size_t

Last edited on
2) yes. I dislike the word for this, integer value is just as good and avoids confusion with math. I think you got it right, not 100% sure on the exact definition (eg whether a character is always considered an integral value or only when its used for integer or incremental type work?) in all contexts.

3) switches represent to some degree electrical circuit like behavior. That aside, the bigger reason is that they are where possible implemented (optimized into) as a lookup table, such that case[value] = action which is not possible to do with floating point values. Char is a type of integer. And, it works on all integral values :P not just int and char. Works fine on all the 42+ *** different integer types, in other words.

4) as far as I know they are redundant. Its just there because all STL containers (string is a container) have a .size, but for a string, .length() is the better word in english.

5) size_t is one of the aforementioned 42+ integer types, yes. Don't care what its size in bytes is. Its correct for the in-use compiler and platform. It tends to be what we used to call the machine word size, which is typically the size of a pointer on that machine, and also the size of a register usually. None of that is set in stone, though. Its really just another integer. The language itself uses this one a lot to return the value to the user: that is, many c++ methods return a size_t to you, and you should get used to seeing it and using it.

*** not kidding.
word. long. long long. unsigned long long. uint64_t. int. size_t. short. unsigned short. int64_t. int32_t. unsigned int. char. unsigned char. byte (less common but oft defined). bool. And the 32 and 16 and 8 bit versions of the int?_t and their unsigned friends. and then microsoft has 2 or 3 entire sets that rename them all if you use visual studio, the all caps nonsense WORD, DWORD, BYTE, BOOL, INT, UINT, .. and who knows what I have forgotten this morning. And every single one of them is just an integer, of one of 4 sizes (8, 16, 32, or 64 bits) which can be in 2's complement or not (signed or unsigned). 8 entities, close to or over 50 names in use.
Last edited on
> What is meant by an "integral"?

Relating to numbers:
An "integral number" is an integer. I've always thought of integer as the noun, and integral as the adjective.

The standard treats integral type and integer type as synonyms.
A synonym for integral type is integer type. https://eel.is/c++draft/basic.fundamental#11


> "size_t is an unsigned integral type". But this is not true on x64

It is true on all platforms; unsigned long long is an unsigned integral type.
> Why is a switch-case construct limited to only integer & char?
> You can compare if (3.14 < 3.1415) just fine, so why not for switch?

One reason is that a construct such as this:
1
2
3
4
5
6
switch( x ) // x is of type double
{
	case 1.0000000000000000001: foo() ;  break ;
	case 1.0000000000000000002 /* error: duplicate case label? */ : bar() ;  break ;
        // ...
}

may be valid on one implementation and invalid on another. Worse, we wouldn't know at compile-time: it would depend on the run-time floating point environment.
5) the sizes of the fundamental, built-in types in C++ can vary in size due to the processor (32-bit vs. 64-bit), the OS and/or the implementation of the compiler used. Never assume anything about the size of a data type, ever. I don't now 'cuz I learned the hard way to not wear donkey ears.

https://en.cppreference.com/w/cpp/language/types

Try this, and if your compiler and processor supports 64-bit try it as 32- and 64-bit if possible:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

int main()
{
   std::cout << "Computing the size of some C and C++ built-in variable types\n\n";

   std::cout << "Size of bool:               " << sizeof(bool) << '\n';
   std::cout << "Size of char:               " << sizeof(char) << '\n';
   std::cout << "Size of wchar_t:            " << sizeof(wchar_t) << '\n';
   std::cout << "Size of unsigned short int: " << sizeof(unsigned short) << '\n';
   std::cout << "Size of short:              " << sizeof(short) << '\n';
   std::cout << "Size of unsigned long int:  " << sizeof(unsigned long) << '\n';
   std::cout << "Size of long:               " << sizeof(long) << '\n';
   std::cout << "Size of int:                " << sizeof(int) << '\n';
   std::cout << "Size of unsigned int:       " << sizeof(unsigned int) << '\n';
   std::cout << "Size of float:              " << sizeof(float) << '\n';
   std::cout << "Size of double:             " << sizeof(double) << "\n\n";

   std::cout << "Size of std::size_t:        " << sizeof(std::size_t) << "\n\n";

   std::cout << "The output can change with compiler, processor type and OS\n\n";

   std::cout << "C++11 added several new fundamental variable types.\n";
   std::cout << "The values can change whether compiled as 32 or 64 bit.\n\n";

   std::cout << "Size of char16_t:           " << sizeof(char16_t) << '\n';
   std::cout << "Size of char32_t:           " << sizeof(char32_t) << '\n';
   std::cout << "Size of unsigned long long: " << sizeof(unsigned long long) << '\n';
   std::cout << "Size of long long:          " << sizeof(long long) << '\n';
   std::cout << "Size of long double:        " << sizeof(long double) << '\n';
   std::cout << "Size of nullptr:            " << sizeof(nullptr) << '\n';
}

32-bit with Visual Studio:
Computing the size of some C and C++ built-in variable types

Size of bool:               1
Size of char:               1
Size of wchar_t:            2
Size of unsigned short int: 2
Size of short:              2
Size of unsigned long int:  4
Size of long:               4
Size of int:                4
Size of unsigned int:       4
Size of float:              4
Size of double:             8

Size of std::size_t:        4

The output can change with compiler, processor type and OS

C++11 added several new fundamental variable types.
The values can change whether compiled as 32 or 64 bit.

Size of char16_t:           2
Size of char32_t:           4
Size of unsigned long long: 8
Size of long long:          8
Size of long double:        8
Size of nullptr:            4

64-bit with Visual Studio:
Computing the size of some C and C++ built-in variable types

Size of bool:               1
Size of char:               1
Size of wchar_t:            2
Size of unsigned short int: 2
Size of short:              2
Size of unsigned long int:  4
Size of long:               4
Size of int:                4
Size of unsigned int:       4
Size of float:              4
Size of double:             8

Size of std::size_t:        8

The output can change with compiler, processor type and OS

C++11 added several new fundamental variable types.
The values can change whether compiled as 32 or 64 bit.

Size of char16_t:           2
Size of char32_t:           4
Size of unsigned long long: 8
Size of long long:          8
Size of long double:        8
Size of nullptr:            8

A different compiler, say MinGW, on the same computer and OS may have one or more type sizes different. long double was the first data type I noticed having different sizes. 32-bit with MinGW a long double's size is 12 bytes, 64-bit it's 16 bytes. Same OS, different compiler implementation.

Tattoo this on the inside of your eyelids, "Never assume* anything about the sizes of a data type. Always test them."

Don't think also should you upgrade your compiler data type sizes haven't changed. Most likely they haven't, but the compiler implementation might have changed their data model.

Knowing the sizes of data types isn't going to be something mission critical for most apps, admittedly. But it isn't something one should leave to chance or ignore either.

*What happens when you assume? You make an "ass" out of "u" and "me."
re 4).

https://cplusplus.com/reference/string/string/size/

states that the returned value of .size()/.length() is the number of bytes. This is true for ASCII based strings (std::string). But for std::wstring (based upon wchar_t - 16 bits) then it is the number of chars - not number of bytes used. Same for std::u16string and std::u32string etc. See https://en.cppreference.com/w/cpp/string/basic_string/size

Consider this simple test code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <string>
#include <iostream>

int main() {
	const std::string str { "qwerty" };

	std::cout << "as ASCII - " << str << "  " << str.size() << "  " << str.length() << "  " << str.size() * sizeof(str[0]) << " bytes" << '\n';

	const std::wstring w { L"asdfgh" };

	std::wcout << "as wchar_t - " << w << "  " << w.size() << "  " << w.length() << "  " << w.size() * sizeof(w[0]) << " bytes" << '\n';

	const auto d { (char*)w.data() };

	for (int i = 0; i <= w.size() * sizeof(w[0]); ++i)
		std::cout << (int)d[i] << ' ';

	std::cout << '\n';

	std::u32string u { U"zxcvbn" };

	std::cout << "as u32" << "  " << u.size() << "  " << u.length() << "  " << u.size() * sizeof(u[0]) << " bytes" << '\n';

	const auto du { (char*)u.data() };

	for (int i = 0; i <= u.size() * sizeof(u[0]); ++i)
		std::cout << (int)du[i] << ' ';

	std::cout << '\n';
}


which displays:


as ASCII - qwerty  6  6  6 bytes
as wchar_t - asdfgh  6  6  12 bytes
97 0 115 0 100 0 102 0 103 0 104 0 0 0
as u32  6  6  24 bytes
122 0 0 0 120 0 0 0 99 0 0 0 118 0 0 0 98 0 0 0 110 0 0 0 0 0 0 0


Note that there's no in-built way (AFAIK) to directly display a std::u32string
Last edited on
3) So switches are too specialized for the optimization of integers and the look-up table. Got it!!

5) It is integral that we don't confuse integral with the area of a mathematical function integral. Actually, I had first seen this "size_t is the unsigned integer type" and wrote in my notes "size_t = unsigned int" and since then I was elated to finally know what size_t meant. Apparently, so much so that I could not pry myself from seeing integral/integer to represent the collection of all those crazy named int's.

Now if I just stopped and really looked and thought some more, but honestly, I just can't look at documents and I really just skim them. So, when I skimmed this, all I saw was size_t = unsigned int. Very dangerous for me and future document browsing.

@George P
I was just thinking of needing to make one of those today & just gradually add them as I see them...thanks for a head start.
3) ???? switch does work with int ???
@protoseep, tattoo this on the inside of your eyelids as well [:)]:

A data type (char, for example) and a pointer to that data type (char*) are for all practical purposes two different data types, and likely to have different storage requirements.

When talking about the storage requirements for a data type remember the C++ standard guarantees the type will require at least X bytes/Y bits. There is no requirement a type can't have a larger width.

C++11 introduced (via the C library) fixed width integer types.

https://en.cppreference.com/w/cpp/types/integer

If your app needs an exact width for a type then the fixed width integer types might be what you should consider.

Personally I don't really care what size a type occupies, I just use whatever I need. A short or an int/long or long long.

I have dozens of mini code projects I created to help learn various aspects of C++. That code for showing the size of data types is one such project I have saved.

C++20 code snippets are common now. Modules and std::format!
Re size_t. Note that this is an unsigned type. When mixing signed and unsigned type, you go down down a rabbit hole and through the looking glass! Consider:

1
2
3
4
5
6
7
8
9
10
11
#include <string>
#include <iostream>
#include <iomanip>

int main() {
	const std::string s { "qwerty" };

	std::cout << "size is " << s.size() << '\n';

	std::cout << "-1 < " << s.size() << " is " << std::boolalpha << (-1 < s.size()) << '\n';
}


which displays:


size is 6
-1 < 6 is false


and we all go loopy-loo. Nurse!

When mixing signed and unsigned, signed are 'promoted' to unsigned. So a negative signed type is 'promoted' to a very large unsigned type!

Be very careful.

Many functions return a type of size_t (.size() etc). You'll often see code that uses these to initialise an int variable (to avoid having to deal with unsigned numbers) - but the compiler will usually squeal about this. Or they are used in a comparison with a signed quantity (as in the simple example above) - and boom!
@seeplus

states that the returned value of .size()/.length() is the number of bytes. This is true for ASCII based strings (std::string). But for std::wstring (based upon wchar_t - 16 bits) then it is the number of chars - not number of bytes used. Same for std::u16string and std::u32string etc. See https://en.cppreference.com/w/cpp/string/basic_string/size


Yes, that was my concern...the wording. It better not return the number of bytes for those other strings and I was certain that I would see that it didn't in the back of my mind and that the wording needed to be changed. As you pointed out the documentation wording lines up perfectly...."Returns the number of CharT elements in the string".

Never played with those types of strings, but it was a good run. So, wait are those the actual UTF encoding & is that it? That is all there is to encoding in UTF? What else can those collection of strings be called?

Interesting how they translate the ASCII right into the first byte for easy transfers directly from ASCII & use the rest of the empty bits for additional characters beyond ASCII.

@George P
My book mentions int8_t & uint8_t (16-64) & it is so cool to be able to set the bits. Never seen fast & least yet.
@seeplus
 
3) ???? switch does work with int ???

Oh no, what are you trying to tell me? Switches work on ints & chars & enums, the latter of which are integral based....NO?
> Switches work on ints & chars & enums

Yes. Also on class types which are contextually convertible to one of those types.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

struct my_type
{
    int first ;
    int second ;
    constexpr explicit my_type( int a = 0, int b = 0 ) noexcept : first(a), second(b) {}
    constexpr operator int() const noexcept { return first + second ; }
};

constexpr my_type operator"" _mt( unsigned long long n ) noexcept { return my_type( int(n) ) ; }

int main()
{
    constexpr my_type seven = 7_mt ;

    int i ;
    std::cin >> i ;
    my_type mt(i) ;

    switch(mt)
    {
        case 5 : std::cout << "5\n" ; break ;
        case my_type(3) : std::cout << "3\n" ; break ;
        case seven : std::cout << "7\n" ; break ;
        case 123_mt : std::cout << "123\n" ; break ;
        default : std::cout << "something else\n" ;
    }
}
protoseepp wrote:
Switches work on ints & chars & enums

If you were to ever see code for a WinAPI Desktop app you'd likely see a switch statement that uses #defined values for case labels (this is NOT a complete example! It will not compile!):
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// processes the messages that Windows sends to the application ================
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   // choose which Windows messages you want to use
   switch (message)
   {
   case WM_PAINT:
      HDC         hdc;
      PAINTSTRUCT ps;
      hdc = BeginPaint(hwnd, &ps);

      // draw some text centered in the client area
      RECT rect;
      GetClientRect(hwnd, &rect);
      DrawText(hdc, TEXT("Hello, Windows!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

      EndPaint(hwnd, &ps);
      return S_OK;

   case WM_DESTROY:
      // exit the application
      PostQuitMessage(0);
      return S_OK;
   }

   // let Windows process any unhandled messages
   return DefWindowProc(hwnd, message, wParam, lParam);
}

The #defines are a way of making hoo-man readable cases instead of using magic numbers like 1504458.

[ETA]: I checked out Winuser.h, the header file where the window messages are defined. Line 1006 of 6, 531 lines: #define WM_PAINT 0x000F

I believe I like using WM_PAINT instead of 0x000F.
Last edited on
Just so that no one gets the wrong idea: There are few reasons to use #define for constants nowadays. It's usually better to use const or enum instead.

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es31-dont-use-macros-for-constants-or-functions
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#enum1-prefer-enumerations-over-macros
The Desktop WinAPI isn't C++, it is C based, though it can be compiled as C++. C doesn't have all the fancy-dancy features that C++ has.

Winuser.h is a legacy header, not new code. Blame MS for retaining #defines.
Pages: 1234... 10