C++ Review Questions

Pages: 1... 5678910
I was just thinking of this again the other day & thought they may add something to C++23 and then quickly thought...naaaa, if they didn't add one by now they wouldn't on the next one.

This is phenomenal & long overdue, thanks!

Haha, yup....MAGIC!
"A common workaround is to define a class type with all of the conversion operators and overloaded arithmetic operators to make it behave as much as possible like a built-in type. But that approach is cumbersome and incomplete, requiring inline assembly or other compiler-specific MAGIC to generate efficient code."
Last edited on
Note that those floating-point types are optional features so make sure you know they are supported with the compilers and platforms that you care about before using.
Thanks Peter, although I did not read the entire article, I did notice "16-bit floating-point support is becoming more widely available in both hardware (ARM CPUs, NVIDIA GPUs, and, as of recently, Intel CPUs) and software (OpenGL, CUDA, and LLVM IR)"
Even if a vendor will support the new optional 16-bit floating point types doesn't mean the implementation will have any meaningful difference(s) from the current floating point types.

Look at Visual C++'s long vs. long double implementation. Those two are identical in size and AFAIK precision.
Like <stdint.h> types, if the implementation supports a type called "std::float16_t", then it better actually be a 16-bit float. It's less ambiguous than the historical uselessness of "long double".
Note that std::float16_t is 16 bits (not 16 bytes), which is half the size of a typical float, and the format is specified exactly. For more information see "Table N" in the proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html#extended-wording
Last edited on
Heh, thanks for pointing out these optional C++ stdlib floating point types are likely gonna end up less useful for precision than the current C++ standard floating point types.

Even the MSVC++ implementation.
No kidding...I really wish they would put in boost floats too.

QUESTION 11)
This one is a reaffirmation, I hope.
If you have a class President (this one was a singleton class), & the line
 
static President& GetInstance()

and you decided to add "const" to this...
 
static const President& GetInstance()


Then ABSOLUTELY no data member can change values in the class? You can refer to const & literal values, but you cannot change a single one ANYWHERE in the class? I just had an odd, but pretty cool thing happen to me. I had another method that made a change to the class members, but was not used in main(). The method showed up after you hit the . (dot) operator & after I changed it to const to experiment that method disappeared & was no longer available.

Pretty cool that you can have code in there that makes changes, but that is not actually being used & that the compiler is not fussy about this.
Ah, a President class singleton, I think I know where that's coming from. "Sams Teach Yourself C++ in One Hour a Day."

Which edition of the book?
> Then ABSOLUTELY no data member can change values in the class?

No data member that is part of the externally visible (logical) state of the object can change.
Members declared mutable can be modified even in const objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct A
{
    const int c = 100 ; // always const, always immutable
    int i = 0 ; // non-const in objects of type A, const in objects of type const A
    mutable int m = 9 ; // never const, always mutable

    void foo() // type of this is A*
    {
        i = 300 ; // fine
        m = 300 ; // fine
        c = 300 ; // *** error ***, type of this->c is const int
    }

    void bar() const // type of this is const A*
    {
        i = 300 ; // *** error ***, type of this->c is const int
        m = 300 ; // fine, modify mutable member
        c = 300 ; // *** error ***, type of this->c is const int
    }
};


More information: https://isocpp.org/wiki/faq/const-correctness#logical-vs-physical-const
That const member functions do not modify the objects is to a large extent a convention. The compiler only goes so far to help you avoid modifications.

~

Sometimes you might have a function that is not modifying the object from the class user's point of view, but for technical reason it needs to modify one of its data members. By marking the data member as mutable it's still possible to mark the function as const.

One example is when implementing a "thread-safe class" that uses a std::mutex in each member function to prevent simultaneous access from multiple threads. This would have to be done in both const and non-const member functions. The problem is that locking (and unlocking) the mutex modifies the mutex so normally you would not be allowed to do this inside const member functions (assuming the mutex is a member of the class). The solution is to mark the mutex as mutable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <mutex>

class ThreadSafeInt
{
private:
	int value = 0;
	mutable std::mutex mutex; // remove mutable and you'll get an error in get() 

public:
	void set(int new_value)
	{
		mutex.lock();
		value = new_value;
		mutex.unlock();
	}
	
	int get() const
	{
		mutex.lock();
		int local_copy = value;
		mutex.unlock();
		return local_copy;
	}
};

~

Sometimes there is data that "belongs" to the object but is not actually a data member. In those cases the compiler will not prevent you from modifying the data inside const member functions. Instead it's the programmer who implements the class that becomes responsible for making sure the data is not modified when it shouldn't.

You normally run into this situation when having a class that is implemented using pointers.

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
33
class DynamicInt
{
private:
	int* ptr;

public:
	DynamicInt()
	:	ptr(new int()) 
	{
	}
	
	~DynamicInt()
	{
		delete ptr;
	}
	
	void set(int new_value)
	{
		*ptr = new_value;
	}
	
	int get() const
	{
		// *ptr = 5; // <-- The compiler does not prevent you from doing this. 
                             //     Just don't do it!
		
		return *ptr;
	}
	
	// prevent copy (and move) operations
	DynamicInt(const DynamicInt&) = delete;
	DynamicInt& operator=(const DynamicInt&) = delete;
};

Another example, from the standard library, is std::vector. Internally it contains a pointer to an array where all the elements are stored. It has two overloads of the "subscript operator" (vec[i]). One non-const overload that returns a non-const reference to the element, and one const overload that returns a const reference to the element. Technically, the compiler wouldn't complain if there was just a single const overload that returned a non-const reference but that would allow you to modify elements of a const vector which is undesirable, so that is why two overloads are needed.

https://en.cppreference.com/w/cpp/container/vector/operator_at

1
2
const std::vector<int> vec = {1, 2, 3};
vec[0] = 5; // You wouldn't want to be able to do this, would you? 

Last edited on
@George P
Yes 8th Ed (C++14/17). I blasted through the first 8 chapters & then had to slow down when it came to the OOP chapters & the operators. Then again somewhat blasted through the containers. With this new book I had to slow down like a snail with the first 2 chapters as there was just soooo much info that I had been missing. I am only on chap 5 so far. George, how much of that "Beginning C++20: From Novice to Professional" book have you read, have you finished it and how slowly or fast are you digesting it? Do you like the book, are you finding it too verbose at times?


@JLBorges
I have not seen mutable yet, but thanks I get it. It is covered in chap 12 in my new book.

@Peter87
I don't know about mutex, but I understand it on the surface. The pointer reassignment I wouldn't think the compiler would allow it, but since it was changed from a non-member value it becomes a loophole...interesting to note. I was happy to take the vector subscript returns for granted, but yea it makes sense to have an overload for const vectors.


So let me ask a general question? How do you guys do it, since there is just so much out there? If new C++20 comes out, how long before you know the new stuff inside & out, a year, maybe more? What is your secret, do you just practice, practice, & practice? You guys are on here, so it must mean that you live, eat & breathe C++. I don't think you can expect to know as much as you guys do without spending a great deal of time with the language & all its nuances.

So snippets of code like the singleton & preventing instantiation on the stack & many other ones from my 1st book I can do without looking now. But then something like the tuples, I knew & have not looked at it for some time & it is like...how do you get the element of a tuple...was it...
tuple_get<tupleType>::size; //NO
tuple_size<tupleType>::value; //After a peek

was it...
template<typename T> int StaticTest::staticVal; //NO
template<typename T> int StaticTest<T>::staticVal; //After a peek

I am happier when I can type it out without looking it up & not so happy when I don't.
Does this happen a lot to you guys? How do you deal with it, do you just need more time with it & it comes eventually?
Last edited on
> do you just need more time with it & it comes eventually?

I think one internalises a language feature or design technique when it is used to solve a genuine real life problem. Looking up the syntax till the feature has been used often enough is fine.

Learning something from text book examples alone has its limitations. Among other things, it looks seductive, and often the examples abuse, rather than use, the feature. For instance, smart pointers in this thread: https://cplusplus.com/forum/beginner/284575/#msg1232626

Even for the professional programmer, it is impossible to first learn a whole programming language and then try to use it. A programming language is learned in part by trying out its facilities for small examples. Consequently, we always learn a language by mastering a series of subsets. The real question is not ‘‘Should I learn a subset first?’’ but ‘‘Which subset should I learn first?’’
...
For programming novices, learning the programming language should support the learning of effective programming techniques. ... The emphasis for both novices and experienced programmers should be concepts and techniques. The syntactic and semantic details of C++ are secondary to an understanding of design and programming techniques that C++ supports.

Stroustrup in 'Learning Standard C++ as a New Language' https://stroustrup.com/new_learning.pdf
Mr Z wrote:
So let me ask a general question? How do you guys do it, since there is just so much out there? If new C++20 comes out, how long before you know the new stuff inside & out, a year, maybe more? What is your secret, do you just practice, practice, & practice? You guys are on here, so it must mean that you live, eat & breathe C++. I don't think you can expect to know as much as you guys do without spending a great deal of time with the language & all its nuances.

There is not a big difference between one version of C++ and the next so I can essentially just continue programming as I have done before (C++11 was an exception).

I happen to be interested in reading about the standardisation process and the new things that gets proposed. I also learn new things that I would normally not use while trying to help people on forums like these. Even though I don't study them in detail I learn they exist so that I can look them up later when I think I need them.

Don't be fooled by all the information I write here. I don't know everything in detail. I often look things up, and test things, at least to verify that my knowledge is correct. After programming for a few years you become very good at looking things up. On other forums that has allowed me to sometimes answer questions about Python even though I never made an attempt at learning that language.

Mr Z wrote:
I am happier when I can type it out without looking it up & not so happy when I don't.
Does this happen a lot to you guys? How do you deal with it, do you just need more time with it & it comes eventually?

Having to look up things like library types and functions does not bother me. It's what we have sites like cppreference.com for. Having to look up syntax is also no big deal if I have just forgot and know what I'm looking for.

Things that I use often I can often do it without looking but for things that I use more seldom there is a greater chance that I have to look it up.

The difficult part is not to learn all the syntax. It's to learn how to structure a program, how to think about programming and solve problems, etc. The more you learn the easier it becomes to pick up new things because there are often similarities and a lot of things build on each other.
Last edited on
I am happier when I can type it out without looking it up & not so happy when I don't.
Does this happen a lot to you guys? How do you deal with it, do you just need more time with it & it comes eventually?


I have a multi-monitor set up (as well as a laptop) and I keep one monitor permanently showing a browser with multiple tabs for the different main c++ sites and MS (and one with VS and the third for whatever else I use at the time). Eg. Do I know all the pre-defined concept definitions? - no. If I'm working with concepts then I'll have cppreference.com showing the concepts page whilst coding so I can just glance at it. Same for other aspects. Do I know every possible std::format type? Again, no. I just look at the formatter page. I might have say 10 tabs open in the browser so I can easily switch between them as needed.

I also read various blog sites where new features are likely to be discussed. IMO having an idea of the features available are more important than knowing the exact syntax required for xyz. If you know what's available then when you come to use, you can look up the exact way to use. Then code some simple test programs to become familiar before using in anger in production programs. Obviously some stuff you just to need to know exists - eg z literal suffix.

If you want to know what's available in which C++ version then
https://en.cppreference.com/w/cpp/compiler_support
which also gives references to papers for more info.


Unless you're learning C++ for the first time, you're probably familiar with a specific C++ version eg C++17. That's why there are several books available that assume you have a certain base of knowledge and just deal with the specific features of a new release.
Note that those floating-point types are optional features so make sure you know they are supported with the compilers and platforms that you care about before using.


Looks like MS isn't going to support them as support is specified as N/A. Ahhh...
The thing is, both Clang and GCC supports some of these "extended floating-point types" so I guess all they will have to do is essentially add some typedefs to a header file.

But MSVC doesn't. Relevant discussion here: https://github.com/microsoft/STL/issues/2956

It's interesting what they say about std::float32_t and std::float64_t, that they need to be different types from float and double even if they are the same format. I wonder if that means Clang and GCC also won't support them?

It's quite clear that what most people really want from this is just standard name(s) for the 16-bit floating point type(s). The rest have just been added by the committee because they thought it was A Good Idea™. For 32 and 64-bit floating-point types float and double are often already good enough in practice. I guess std::float128_t could be as useful as std::float8_t but there seems to be much less demand for it.
Last edited on
@Mr. Z,

I just an finishing up my 3rd pass with Beginning C++20. Each time I learn/remember something I didn't know/understand the previous times. In a couple of months I probably will start another pass through the book and the code examples.

The differences IMO between Beginning C++20 and a Sams Learn C++ book? Lots more critically needed detail in BC++20. It is oriented towards programming professionals who have never really done any C++. I'd honestly say some very minimal C++ experience is still kinda sorta needed with BC++, though not a lot.

BC++20 and the various Sams books I have are what I consider bedrock books, the foundation of learning C++. All my other C++ books state they are for someone who already knows C++ but wants more detail into what a particular language standard offers, C++14/C++17, etc.

BC++20 is like a 20 course meal, the Sams books are close to a McD's Happy Meal.
Thanks guys, good to know & it gives me hope.

George P,
I have transcribed a lot of the Sam's pages into digital notes & it makes for a quicker read without the extra fluff. I have transcribed the first 2 BC++20 chapters & if you like I can give them to you since you own the book. I plan on doing the same with more chapters down the road.
I don't need your notes, Mr. Z, I have my own. :)

A lot of my notes consist of code snippets I wrote to help mash a particular concept into my mush brain:
First pass snippet example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <vector>

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
   for ( auto const& x : v ) { os << x << ' '; }
   return os;
}
int main()
{
   std::vector vec1D { 1, 2, 3, 4, 5 };

   std::cout << vec1D << "\n\n";

   std::vector<std::vector<int>> vec2D { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

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

Snippet using C++20 concepts:
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
33
34
35
36
37
38
39
#include <iostream>
#include <vector>
#include <list>

template <typename T>
concept Container = requires(T t)
{
   std::begin(t);
   std::end(t);
};

template <Container C>
std::ostream& operator<<(std::ostream& os, const C& v)
{
   for ( auto const& x : v ) { os << x << ' '; }
   return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<T>>& v)
{
   for ( auto const& x : v ) { os << x << '\n'; }
   return os;
}

int main()
{
   std::vector vec1D { 1, 2, 3, 4, 5 };

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

   std::list lst1D { 4, 5, 6, 7 };

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

   std::vector<std::vector<int>> vec2D { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

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

Now I just have to let the brain cells squeal and grind to figure out how to be able to display a generic 2D container as I do a 2D vector.

I have a few header-only/module interface files I've mashed together: https://github.com/GeorgePimpleton/misc_files
Pages: 1... 5678910