How it works...

We have now created two classes, TimeSaver1 and TimeSaver2, which look almost identical and do identical jobs. Both classes open a file in their constructors and call the Update function, which writes a timestamp into an open file.

Similarly, their destructors invoke the same Update function to add a second timestamp and close the file descriptor.

TimeSaver1, however, breaks the A0-1-2 rule and is unsafe. Let's take a closer look at this. Its Update function invokes two functions, time and write. Both functions may fail, returning proper error code, but our implementation ignores it:

    time(&tm);
Write(fd, &tm, sizeof(tm));

Also, the destructor of TimeSaver1 closes the open file by calling the close function. This may also fail, returning an error code, which we ignore:

    close(fd);

The second class, TimeSaver2, complies with the requirement. We assign the result of the time call to the tm variable:

    time_t tm = time(&tm);

If Write returns an error, we throw an exception:

    int rv = Write(fd, &tm, sizeof(tm));
if (rv < 0) {
throw std::system_error(errno,
std::system_category(),
"Failed to write to file");
}

Similarly, we throw an exception if close returns an error:

    if (close(fd) < 0) {
throw std::system_error(errno,
std::system_category(),
"Failed to close file");
}

To mitigate this kind of issue, the C++17 standard introduced a special attribute called [[nodiscard]]. If a function is declared with this attribute, or it returns a class or enumeration marked as nodiscard, the compiler should display a warning if its return value is discarded. To use this feature, we created a custom wrapper around the write function and declared it nodiscard:

[[nodiscard]] ssize_t Write(int fd, const void* buffer,
ssize_t size) {
return ::write(fd, buffer, size);
}

We can see this in the compiler output when we build our application, which also means we have the opportunity to fix it:

In fact, the compiler was able to recognize and report another issue in our code that we will discuss in the next recipe.

If we build and run the application, we won't see any output since all writes go to files. We can run the ls command to check that the program produces a result, as follows:

$ ls timestamp*

From this, we get the following output:

As expected, two files are created by our program. They should be identical, but they are not. The file created by TimeSaver1 is empty, meaning its implementation has an issue.

The file generated by TimeSaver2 is valid, but does that mean that its implementation is 100 percent correct? Not necessarily, as we'll see in the next recipe.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.40.177