C++ Programming Techniques: ‘Lazy Evaluation’ – Enhancing Program Efficiency with Procrastination

Procrastination is clearly the culprit behind reduced efficiency, so why can it actually improve efficiency in programming, and is referred to as ‘lazy evaluation’?The key point is that the user may ultimately not need the computation results; as long as we keep delaying, that part of the computation does not need to be executed. A concrete example will illustrate the advantages of ‘lazy evaluation’ more intuitively:1. Reference CountingConsider the following code:

std::string A = "Hello";std::string B = A;std::cout << B;

According to the original execution method, a copy of A is created for B, which incurs a certain cost.In the style of ‘lazy evaluation’, we treat B as a reference to A; as long as there are no statements that independently modify A or B, we never need to create a copy of A for B.2. Distinguishing Read and WriteTake a look at this:

std::string str = "Hello World!";std::cout << str[5];str[5] = '-';

In the above, the second and third statements both use the operator[] function, but one is for reading, and the other is for writing; the cost of these two operations is significantly different.Can we make operator[] distinguish between reading and writing? This requires combining ‘lazy evaluation’ with ‘proxy classes’, which will be discussed in detail later.3. Lazy RetrievalNow consider a class object that is generally stored in a database and read out when used. Clearly, reading a complete object each time is time-consuming, so we can read a member only when it is used, delaying the retrieval of other unused members:

class Object{public:    Object():f1(0),f2(0){}    void Fun1();    void Fun2() const;private:    mutable int* f1;    mutable std::string* f2;};// Fun2 needs to use f2void Object::Fun2() const{    if(f2 == 0){ read f2 }}

As seen, the members of the object are all pointers, initialized to nullptr. Only when a member function is used do we read the specific content, which is why we use mutable, to prevent const member functions from being unable to read and assign values to members.If checking whether members exist each time is cumbersome, we can use smart pointers, and they do not need to be declared as mutable (as they are actually contained within the smart pointer), which will be discussed later.4. Expression Lazy EvaluationSome expressions are not computed immediately; they are computed when needed. Suppose we have a matrix class Matrix:

// 1000*1000 matrixMatrix<int> A(1000,1000);Matrix<int> B(1000,1000);// expression lazy evaluationMatrix<int> C = A * B;

We do not compute A * B immediately; we wait until C is needed to compute it. Furthermore, if only part of C is used, we only compute that part.

Leave a Comment