לדלג לתוכן

2.6 - ייצוג מצב ופעולות בספרייה - פתרון

פתרון - קובץ ריק הוא הצלחה

הפונקציה inspect_size מן ההרצאה כבר משמרת את ההבחנה. בחלופת FileSize, גם bytes שערכם אפס הם תוצאה תקינה. בחלופת Missing אין גודל קובץ כלל, ובחלופת Failure נשמר מידע נוסף על סיבת הכשל.

אפשר לכתוב הצגה באמצעות visitor:

#include <cstdio>
#include <type_traits>

void show(const SizeResult& result) {
    std::visit([](const auto& value) {
        using T = std::decay_t<decltype(value)>;
        if constexpr (std::is_same_v<T, FileSize>) {
            std::printf("%llu bytes\n",
                        static_cast<unsigned long long>(value.bytes));
        } else if constexpr (std::is_same_v<T, Missing>) {
            std::puts("file is missing");
        } else {
            std::fprintf(stderr, "%s\n",
                         value.error.message().c_str());
        }
    }, result);
}

הקטע מצטרף לקובץ שמגדיר את שלוש החלופות ואת SizeResult. אם מרחיבים את ה־variant בעתיד, צריך לעדכן גם את הטיפול; ספרייה רחבה יותר יכולה להשתמש במבנה visitors שמחייב overload מפורש לכל חלופה.

שני מונים

הבדיקה הבאה מצטרפת ל־make_counter:

#include <cassert>

int main() {
    auto first = make_counter(5);
    auto second = make_counter(5);
    assert(first() == 6);
    assert(first() == 7);
    assert(second() == 6);
}

כל closure שומרת עותק משלה. בגרסת reference היה נשמר קשר לפרמטר start של הקריאה ל־factory, שחייו הסתיימו לפני השימוש במונה. המעטפת std::function אינה מאריכה את חיי הפרמטר המקורי.

מדידה עם יחידה

הקוד הבא הוא תוכנית מדידה עצמאית:

#include <chrono>
#include <cstdint>
#include <cstdio>

int main() {
    const auto start = std::chrono::steady_clock::now();
    std::uint64_t result = 0;
    for (std::uint64_t i = 0; i < 100000; ++i) {
        result = (result * 33) ^ i;
    }
    const auto elapsed = std::chrono::steady_clock::now() - start;
    const auto micros =
        std::chrono::duration_cast<std::chrono::microseconds>(elapsed);
    std::printf("result=%llu elapsed=%lld us\n",
                static_cast<unsigned long long>(result),
                static_cast<long long>(micros.count()));
}

החשבון הוא unsigned ולכן wraparound חלק מהחוזה שלו. הפלט כולל את result כדי שהחישוב יהיה נצפה, אבל עדיין בודקים את הקוד שנוצר ולא מניחים שכל איטרציה נראית בדיוק כמו במקור.

תוצאה של אפס מיקרושניות יכולה לנבוע מרזולוציה או מחיתוך יחידות. זאת מדידה קטנה עם overhead, ולא benchmark שמוכיח יתרון של ספרייה.

בחירת תוצאה

בחיפוש בזיכרון optional יכולה להספיק כאשר אין שגיאת סביבה שצריך להבחין בה. בקריאת קובץ או parser נרצה לשמור שגיאה עם הקשר, ולכן expected נתמכת או variant של הצלחה ושגיאה מתאימות יותר.

הבחירה נקבעת לפי מידע שהקורא צריך כדי להגיב. אין יתרון בייצוג קצר שמוחק את ההבדל בין קלט חסר, כשל הרשאה ופורמט פגום.