BjΓΆrn Straustrup Answers Top 5 C ++ Questions with Stack Overflow

In anticipation of the start of the course "C ++ Developer" prepared a translation of interesting material.





Marielle Frank and Sonny Lee, authors of the Learn C ++ course on Codecademy, recently got the opportunity to interview Dr. BjΓΆrn Straustrup, creator of C ++.

As part of this interview, he answered the C ++ questions that got the most votes on Stack Overflow. Although all the interviews are worth reading, Codecademy generously allowed us to share part of it.

If you have ever wondered if there are definitively comprehensive answers on Stack Overflow, then here is something closest to this that you can get for sure (although we expect someone to disagree).

Why is processing a sorted array faster than processing an unsorted array?



Note: This question is the number 1 that received the most votes on the Stack Overflow of all time.


Sounds like a question from an interview. It's true? How did you know that? It’s bad to answer questions about efficiency without taking preliminary measurements, so it’s important to know how to measure them.
So, I checked on a vector of a million integers and got:

    32995 
          125944 

     18610 
          133304 

     17942 
          107858 


I ran this a few times to make sure. Yes, this phenomenon is real. My main code was:

void run(vector<int>& v, const string& label)
{
    auto t0 = system_clock::now();
    sort(v.begin(), v.end());
    auto t1 = system_clock::now();
    cout << label 
         << duration_cast<microseconds>(t1 β€” t0).count() 
         << " milliseconds\n";
}

void tst()
{
    vector<int> v(1'000'000);
    iota(v.begin(), v.end(), 0);
    run(v, "already sorted ");
    std::shuffle(v.begin(), v.end(), std::mt19937{ std::random_device{}() });
    run(v, "shuffled    ");
}


At least, this phenomenon is real with this compiler, the standard library and optimizer settings. Different implementations can give (and give) different answers. In fact, someone did a more systematic study (a quick search on the Internet will help you find it), and most implementations show this effect.

One of the reasons is branch prediction: the key operation in the sorting algorithm is β€œif (v [i] <pivot]) ...” or the equivalent. For a sorted sequence, this test is always true, while for a random sequence, the selected branch changes randomly.

Another reason is that when the vector is already sorted, we never need to move the elements to the correct position. The effect of these small details gives a factor of approximately five or six, which we observed.

Quicksort (and sorting in general) is a complex study that has attracted some of the greatest minds of computer science. A good sorting function is the result of choosing a good algorithm and attention to equipment performance during its implementation.
If you want to write efficient code, you need to take into account the architecture of the machine.
β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
Sorry for the intervention. Just a reminder that the Stack Overflow podcast is back! Drop by and hear an interview with our new CEO.

What is the -> operator in C ++?




This is an old trick question. In C ++ there is no operator ->. Consider the following:

if (p-->m == 0) f(p);


This, of course, looks like there is some kind of operator -> and with a suitable declaration p and m, you can even compile and run this:

int p = 2;
int m = 0;
if (p-->m == 0) f(p);


This actually means: see if p-- is greater than m (the way it is), and then compare the result (true) with 0. Well, true! = 0, so the result is false and f () is not called. In other words:

if ((p--) > m == 0) f(p);


Please do not spend too much time on such questions. They were popular for confusing beginners even before the invention of C ++.

The best guide and list of C ++ books



Unfortunately, there is no canonical list of C ++ books. This, in principle, cannot be. Not everyone needs the same information, not everyone has the same experience, and C ++ best practices are constantly evolving.

I did a little research on the Internet and found an amazing set of recommendations. Many were seriously outdated, and some were simply bad. A beginner looking for a good book without guidance will be very confused!

You really need a book because the methods that make C ++ effective are not easy to find on several blogs on specific topics, and of course blogs also suffer from errors, obsolescence, and poor explanations. Often they also focus on advanced new topics and ignore the basic principles.

I recommend myProgramming: Principles and Practice of using C ++ (2nd edition) for people who are just starting to learn how to program, and C ++ Tour (2nd edition) for people who are already programmers and who need to get familiar with modern C ++. People with a strong mathematical background can start with Discovering Modern C ++: An Intensive Course for Scientists, Engineers, and Programmers Peter Gottschling.

Once you start using C ++ for real, you will need a set of guidelines to distinguish between what can be done and what is good practice. For this, I recommend the C ++ Core Guidelines on GitHub.

For a good brief explanation of the individual language features and functions of the standard library, I recommendwww.cppreference.com .

#4. What are the differences between a pointer variable and a reference variable in C ++?



To learn more about links and pointers, check out Learn C ++ .

Both are represented in memory as a machine address. The difference is in their use.
To initialize the pointer, you give it the address of the object:

int x = 7;
int* p1 = &x;
int* p2 = new int{9};


To read and write through a pointer, we use the dereference operator (*):

*p1 = 9;       // write through p1
int y = *p2;   // read through p2


When we assign one pointer to another, they will both point to the same object:

p1 = p2;       //  p1  p2    int   9
*p2 = 99;      //  99  p2
int z = *p1;   //   p1, z  99 (  9)


Note that a pointer can point to different objects during its life cycle. This is the main difference from links. The link is attached to the object when it is created and cannot be converted into a link to another.

For references, dereferencing is implicit. You initialize the link with the object, and the link gets its address.

int x = 7;
int& r1 = x;
int& r2 = *new int{9};


The new operator returns a pointer, so I had to dereference it before the assignment, using it to initialize the link.

For reading and writing through a link, we simply use the link name (without explicit dereferencing):

r1 = 9;        //   r1
int y = r2;    //   r2


When we assign one link to another, the specified value will be copied:

r1 = r2;       //  p1  p2     9
r1 = 99;       //  99  r1
int z = r2;    //   r2, z  9 (  99)


Both references and pointers are often used as arguments to a function:

void f(int* p)

{
    if (p == nullptr) return;
    // ...
}

void g(int& r)
{
    // ...
}

int x = 7;
f(&x);
g(x);


There may be a pointer nullptr, so we should check to see if it points to anything. About the link, you can initially assume that it refers to something.

#5. How to iterate over string words?




Use stringstream, but how do you define a "word"? Think: "Mary had a little lamb." The last word is β€œlamb” or β€œlamb.”? If there is no punctuation, this is easy:

vector<string> split(const string& s)
{
    stringstream ss(s);
    vector<string> words;
    for (string w; ss>>w; ) words.push_back(w);
    return words;
}

auto words = split("here is a simple example");   // five words
for (auto& w : words) cout << w << '\n';


or simply:

for (auto& w : split("here is a simple example")) cout << w << '\n';


By default, the >> operator skips spaces. If we need arbitrary sets of delimiters, things get a little more confusing:

template<typename Delim>
string get_word(istream& ss, Delim d)
{
    string word;
    for (char ch; ss.get(ch); )    //  
        if (!d(ch)) {
            word.push_back(ch);
            break;
        }
    for (char ch; ss.get(ch); )    //  
        if (!d(ch))
            word.push_back(ch);
        else
            break;
    return word;
}


d is an operation telling if the character is a delimiter, and I return "" (empty string) to indicate that there was no word to return.

vector<string> split(const string& s, const string& delim)
{
    stringstream ss(s);
    auto del = [&](char ch) { for (auto x : delim) if (x == ch) return true; return false; };

    vector<string> words;
    for (string w; (w = get_word(ss, del))!= ""; ) words.push_back(w);
    return words;
}

auto words = split("Now! Here is something different; or is it? ", "!.,;? ");
for (auto& w : words) cout << w << '\n';


If you have a C ++ 20 Range library, you do not need to write something like this, but you can use split_view.

Bjarn Straustrup is a technical partner and managing director of Morgan Stanley New York and a visiting professor at Columbia University. He is also the creator of C ++.

For more information about C ++ 20, see: isocpp.org .


That's all. See you on the course !

All Articles