c++ - दो शून्य-अर्ग कंस्ट्रक्टरों को अलग करने के लिए मुहावरेदार तरीका




performance constructor (5)

आप अपनी कक्षा के लिए दो-चरण के प्रारंभ पर विचार कर सकते हैं:

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() = default;

    void set_zero() {
       std::fill(std::begin(counts), std::end(counts), 0u);
    }
};

ऊपर दिया गया कंस्ट्रक्टर सरणी को शून्य पर आरंभीकृत नहीं करता है। सरणी के तत्वों को शून्य पर सेट करने के लिए, आपको निर्माण के बाद सदस्य फ़ंक्शन set_zero() को कॉल करना होगा।

मेरे पास इस तरह एक वर्ग है:

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    // more stuff

};

आमतौर पर मैं डिफ़ॉल्ट (शून्य) को दिखाना चाहता हूं जैसा कि दिखाया गया है।

प्रोफाइलिंग द्वारा पहचाने गए चयनित स्थानों पर, हालांकि, मैं सरणी आरंभीकरण को दबा देना चाहता हूं, क्योंकि मुझे पता है कि सरणी को ओवरराइट किया जाने वाला है, लेकिन संकलक यह पता लगाने के लिए पर्याप्त स्मार्ट नहीं है।

इस तरह के "माध्यमिक" शून्य-अर्ग कंस्ट्रक्टर बनाने के लिए एक मुहावरेदार और कुशल तरीका क्या है?

वर्तमान में, मैं एक टैग वर्ग का उपयोग कर रहा हूं uninit_tag जिसे एक डमी तर्क के रूप में पारित किया गया है, जैसे:

struct uninit_tag{};

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    event_counts(uninit_tag) {}

    // more stuff

};

फिर मैं no-init कन्स्ट्रक्टर को event_counts c(uninit_tag{}); तरह कॉल करता हूं event_counts c(uninit_tag{}); जब मैं निर्माण को दबाना चाहता हूं।

मैं उन समाधानों के लिए खुला हूं जिनमें डमी वर्ग का निर्माण शामिल नहीं है, या किसी तरह से अधिक कुशल हैं, आदि।


आपके पास पहले से मौजूद समाधान सही है, और ठीक वही है जो मैं देखना चाहता हूं कि क्या मैं आपके कोड की समीक्षा कर रहा था। यह यथासंभव कुशल, स्पष्ट और संक्षिप्त है।


मुझे लगता है कि टैग क्लास या बूल की तुलना में एक एनम एक बेहतर विकल्प है। आपको किसी संरचना के उदाहरण को पारित करने की आवश्यकता नहीं है और यह कॉलर से स्पष्ट है कि आपके पास कौन सा विकल्प है।

struct event_counts {
    enum Init { INIT, NO_INIT };
    uint64_t counts[MAX_COUNTERS];

    event_counts(Init init = INIT) {
        if (init == INIT) {
            std::fill(counts, counts + MAX_COUNTERS, 0);
        }
    }
};

तब उदाहरण बनाना इस तरह दिखता है:

event_counts e1{};
event_counts e2{event_counts::INIT};
event_counts e3{event_counts::NO_INIT};

मैं इसे इस तरह से करूंगा:

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    event_counts(bool initCounts) {
        if (initCounts) {
            std::fill(counts, counts + MAX_COUNTERS, 0);
        }
    }
};

जब आप event_counts(false) उपयोग करते हैं, तो कंपाइलर सभी कोड को छोड़ने के लिए पर्याप्त स्मार्ट होगा, और आपको अपनी कक्षा के इंटरफ़ेस को इतना अजीब बनाने के बजाय वास्तव में कहने का मतलब है।


यदि कंस्ट्रक्टर बॉडी खाली है, तो इसे छोड़ा या डिफ़ॉल्ट किया जा सकता है:

struct event_counts {
    std::uint64_t counts[MAX_COUNTERS];
    event_counts() = default;
};

फिर डिफ़ॉल्ट इनिशियलाइज़ेशन event_counts counts; counts.counts को छोड़ देगा। counts.counts रूप से counts.counts (डिफ़ॉल्ट इनिशियलाइज़ेशन एक नो-ऑप है यहां), और वैल्यू इनिशियलाइज़ेशन event_counts counts{}; प्रभावी ढंग से शून्य के साथ इसे भरने, counts.counts है counts.counts





constructor