C ++ में, क्या मैं उसके लिए भुगतान कर रहा हूं जो मैं नहीं खा रहा हूं?


170

आइए C और C ++ में निम्नलिखित हैलो दुनिया उदाहरणों पर विचार करें:

main.c

#include <stdio.h>

int main()
{
    printf("Hello world\n");
    return 0;
}

main.cpp

#include <iostream>

int main()
{
    std::cout<<"Hello world"<<std::endl;
    return 0;
}

जब मैं उन्हें गॉडबोल्ट में असेंबली में संकलित करता हूं, तो सी कोड का आकार केवल 9 लाइनें ( gcc -O3) है:

.LC0:
        .string "Hello world"
main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     rsp, 8
        ret

लेकिन C ++ कोड का आकार 22 लाइनें ( g++ -O3) है:

.LC0:
        .string "Hello world"
main:
        sub     rsp, 8
        mov     edx, 11
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
        xor     eax, eax
        add     rsp, 8
        ret
_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

... जो बहुत बड़ा है।

यह प्रसिद्ध है कि C ++ में आप जो खाते हैं उसके लिए भुगतान करते हैं। तो, इस मामले में, मैं किसके लिए भुगतान कर रहा हूं?


3
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
शमूएल एलवाई


26
eatC ++ से जुड़ा शब्द कभी नहीं सुना । मेरा मानना ​​है कि आप का मतलब है: "आप केवल उसी चीज का भुगतान करते हैं जो आप उपयोग करते हैं "?
जियाको अल्जेटा

7
@GiacomoAlzetta, ... यह एक बोलचाल की भाषा है, जो एक ऑल-यू-कैन-ईट बुफे की अवधारणा को लागू करती है। अधिक सटीक शब्द का उपयोग निश्चित रूप से एक वैश्विक दर्शकों के साथ बेहतर है, लेकिन एक मूल अमेरिकी अंग्रेजी वक्ता के रूप में, शीर्षक मेरे लिए समझ में आता है।
चार्ल्स डफी

5
@ trolley813 मेमोरी लीक का उद्धरण और ओपी प्रश्न से कोई लेना-देना नहीं है। "आप जो भी उपयोग करते हैं उसके लिए आप केवल भुगतान करते हैं" / "आप जो उपयोग नहीं करते हैं उसके लिए भुगतान नहीं करते हैं" का कहना है कि यदि आप किसी विशिष्ट सुविधा / अमूर्त का उपयोग नहीं करते हैं तो कोई प्रदर्शन हिट नहीं लिया जाता है। मेमोरी लीक का इससे कोई लेना देना नहीं है, और यह केवल यह दर्शाता है कि यह शब्द eatअधिक अस्पष्ट है और इसे टाला जाना चाहिए।
जियाको अल्जेटा

जवाबों:


60

आप जो भुगतान कर रहे हैं वह एक भारी पुस्तकालय (कंसोल में मुद्रण के रूप में भारी नहीं) को कॉल करने के लिए है। आप किसी ostreamऑब्जेक्ट को इनिशियलाइज़ करते हैं । कुछ छिपे हुए भंडारण हैं। फिर, आप कॉल करते हैं std::endlजो कि एक पर्यायवाची नहीं है \niostreamपुस्तकालय आप कई सेटिंग को व्यवस्थित करने और प्रोग्रामर के बजाय प्रोसेसर पर बोझ डालने में मदद करता है। यह वह है जिसके लिए आप भुगतान कर रहे हैं।

आइए कोड की समीक्षा करें:

.LC0:
        .string "Hello world"
main:

ओस्ट्रीम ऑब्जेक्ट + कॉट को इनिशियलाइज़ करना

    sub     rsp, 8
    mov     edx, 11
    mov     esi, OFFSET FLAT:.LC0
    mov     edi, OFFSET FLAT:_ZSt4cout
    call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)

coutनई लाइन प्रिंट करने और फ्लश करने के लिए फिर से कॉल करना

    mov     edi, OFFSET FLAT:_ZSt4cout
    call    std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
    xor     eax, eax
    add     rsp, 8
    ret

स्थैतिक भंडारण आरंभीकरण:

_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

साथ ही, भाषा और पुस्तकालय के बीच अंतर करना आवश्यक है।

BTW, यह कहानी का एक हिस्सा है। आपको पता नहीं है कि आपके द्वारा कॉल किए जा रहे कार्यों में क्या लिखा है।


5
एक अतिरिक्त नोट के रूप में, पूरी तरह से परीक्षण यह दिखाएगा कि "ios_base :: Sync_with_stdio (झूठा);" और "Cin.tie (NULL);" प्रिंटआउट की तुलना में तेजी से कॉउट बनाएगा (Printf का प्रारूप स्ट्रिंग ओवरहेड है)। पहला ओवरहेड को यह सुनिश्चित करने से रोकता है कि cout; printf; coutवह क्रम में लिखता है (क्योंकि उनके पास अपने स्वयं के बफ़र हैं)। दूसरा desync coutऔर cin, cout; cinसंभावित रूप से उपयोगकर्ता से पहले जानकारी मांगने का कारण होगा । निस्तब्धता आपको केवल तभी सिंक करने के लिए मजबूर करेगी जब आपको वास्तव में इसकी आवश्यकता होगी।
निकोलस पिपिटोन

हाय निकोलस, इन उपयोगी नोटों को जोड़ने के लिए बहुत-बहुत धन्यवाद।
अरश

"भाषा और पुस्तकालय के बीच अंतर करना आवश्यक है": हाँ, लेकिन मानक भाषा के साथ आने वाला पुस्तकालय हर जगह उपलब्ध है, इसलिए यह हर जगह इस्तेमाल किया जा रहा है (और हाँ, सी मानक पुस्तकालय का हिस्सा है C ++ विनिर्देशन, इसलिए इसका उपयोग वांछित होने पर किया जा सकता है)। जैसा कि "आप यह नहीं जानते कि आप जो कार्य कर रहे हैं उसमें क्या लिखा है": आप स्टेटिकली लिंक कर सकते हैं यदि आप वास्तव में जानना चाहते हैं, और वास्तव में कॉलिंग कोड जिसे आप जांचते हैं वह शायद अप्रासंगिक है।
पीटर - मोनिका

211

तो, इस मामले में, मैं किसके लिए भुगतान कर रहा हूं?

std::coutसे अधिक शक्तिशाली और जटिल है printf। यह लोकेशन, स्टेटफुल फॉर्मेटिंग फ्लैग और बहुत कुछ जैसी चीजों का समर्थन करता है।

यदि आपको उन की आवश्यकता नहीं है, तो उपयोग करें std::printfया std::puts- वे उपलब्ध हैं <cstdio>


यह प्रसिद्ध है कि C ++ में आप जो खाते हैं उसके लिए भुगतान करते हैं।

मैं यह भी स्पष्ट करना चाहता हूं कि C ++ ! = C ++ मानक पुस्तकालय। स्टैण्डर्ड लाइब्रेरी को सामान्य प्रयोजन और "पर्याप्त रूप से तेज़" माना जाता है, लेकिन यह अक्सर एक विशेष कार्यान्वयन की तुलना में धीमा होगा जो आपको चाहिए।

दूसरी ओर, C ++ भाषा अनावश्यक अतिरिक्त छिपी लागतों (जैसे ऑप्ट-इन virtual, कोई कचरा संग्रह) का भुगतान किए बिना कोड लिखना संभव बनाने का प्रयास करती है ।


4
+1 कहने के लिए द स्टेंडर्ड लाइब्रेरी सामान्य-उद्देश्य और "पर्याप्त रूप से तेज़" माना जाता है, लेकिन यह अक्सर एक विशेष कार्यान्वयन की तुलना में धीमा होगा जो आपको चाहिए। कई लोग प्रदर्शन के निहितार्थ बनाम अपने स्वयं के रोल पर विचार किए बिना एसटीएल घटकों का उपयोग करने के लिए ब्लिटली लगते हैं।
क्रेग एस्टे

7
@ क्रैग ओटीओएच मानक पुस्तकालय के कई हिस्से आमतौर पर तेजी से और अधिक सही होते हैं जो आम तौर पर इसके बजाय उत्पादन कर सकते हैं।
पीटर -

2
@ पीटरए.साइडर ओटीओएच, जब एसटीएल संस्करण 20x-30x धीमा है, तो अपनी खुद की रोलिंग अच्छी बात है। मेरा जवाब यहाँ देखें: codereview.stackexchange.com/questions/191747/… उसमें, अन्य लोगों ने भी सुझाव दिया [कम से कम एक आंशिक] अपना रोल।
क्रेग एस्टे

1
@ क्रेगस्टी एक वेक्टर है (प्रारंभिक गतिशील आवंटन के अलावा जो महत्वपूर्ण हो सकता है, इस बात पर निर्भर करता है कि अंततः दिए गए उदाहरण के साथ कितना काम किया जाएगा) C सरणी से कम कुशल नहीं; यह होने के लिए नहीं बनाया गया है। ध्यान रखना चाहिए कि इसे चारों ओर से कॉपी न किया जाए, शुरू में पर्याप्त जगह आरक्षित की जाए, लेकिन यह सब एक सरणी के साथ भी किया जाना चाहिए, और कम सुरक्षित रूप से। आपके जुड़े हुए उदाहरण के संबंध में: हाँ, वैक्टर के एक वेक्टर (जब तक कि अनुकूलित नहीं हो जाता है) एक 2 डी सरणी की तुलना में एक अतिरिक्त अप्रत्यक्ष रूप से उकसाएगा, लेकिन मुझे लगता है कि 20x दक्षता वहां निहित नहीं है, लेकिन एल्गोरिथ्म में।
पीटर - मोनिका

174

आप C और C ++ की तुलना नहीं कर रहे हैं। आप तुलना कर रहे हैं printfऔर std::cout, जो विभिन्न चीजों (स्थानों, स्टेटफुल फॉर्मेटिंग, आदि) में सक्षम हैं।

तुलना के लिए निम्न कोड का उपयोग करने का प्रयास करें। गॉडबोल्ट दोनों फाइलों के लिए एक ही असेंबली बनाता है (जीसीसी 8.2 के साथ परीक्षण किया गया, -ओ 3)।

main.c:

#include <stdio.h>

int main()
{
    int arr[6] = {1, 2, 3, 4, 5, 6};
    for (int i = 0; i < 6; ++i)
    {
        printf("%d\n", arr[i]);
    }
    return 0;
}

main.cpp:

#include <array>
#include <cstdio>

int main()
{
    std::array<int, 6> arr {1, 2, 3, 4, 5, 6};
    for (auto x : arr)
    {
        std::printf("%d\n", x);
    }
}


समकक्ष कोड दिखाने और कारण समझाने के लिए चीयर्स।
हैकलैश

134

आपकी लिस्टिंग वास्तव में सेब और संतरे की तुलना कर रही है, लेकिन अधिकांश अन्य उत्तरों में निहित कारण के लिए नहीं।

आइए देखें कि आपका कोड वास्तव में क्या करता है:

सी:

  • एक तार को प्रिंट करें, "Hello world\n"

सी ++:

  • स्ट्रिंग स्ट्रीम "Hello world"मेंstd::cout
  • std::endlमैनिपुलेटर को स्ट्रीम करेंstd::cout

जाहिरा तौर पर आपका C ++ कोड दोगुना काम कर रहा है। एक निष्पक्ष तुलना के लिए हमें इसे संयोजित करना चाहिए:

#include <iostream>

int main()
{
    std::cout<<"Hello world\n";
    return 0;
}

... और अचानक आपके विधानसभा कोड mainसी के समान दिखते हैं:

main:
        sub     rsp, 8
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
        xor     eax, eax
        add     rsp, 8
        ret

वास्तव में, हम सी और सी ++ कोड लाइन द्वारा लाइन की तुलना कर सकते हैं, और बहुत कम अंतर हैं :

sub     rsp, 8                      sub     rsp, 8
mov     edi, OFFSET FLAT:.LC0   |   mov     esi, OFFSET FLAT:.LC0
                                >   mov     edi, OFFSET FLAT:_ZSt4cout
call    puts                    |   call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
xor     eax, eax                    xor     eax, eax
add     rsp, 8                      add     rsp, 8
ret                                 ret

एकमात्र वास्तविक अंतर यह है कि C ++ में हम operator <<दो तर्कों ( std::coutऔर स्ट्रिंग) के साथ कहते हैं। हम निकट सी eqivalent का उपयोग करके उस मामूली अंतर को भी हटा सकते हैं: fprintfजिसमें स्ट्रीम को निर्दिष्ट करने वाला पहला तर्क भी है।

यह असेंबली कोड छोड़ देता है _GLOBAL__sub_I_main, जो C ++ के लिए उत्पन्न होता है, लेकिन C. नहीं। यह एकमात्र सत्य ओवरहेड है जो इस असेंबली लिस्टिंग में दिखाई देता है ( दोनों भाषाओं के लिए अधिक, अदृश्य ओवरहेड , बिल्कुल)। यह कोड C ++ प्रोग्राम की शुरुआत में कुछ C ++ मानक लाइब्रेरी फ़ंक्शंस का एक-बार सेटअप करता है।

लेकिन, जैसा कि अन्य उत्तरों में बताया गया है, इन दो कार्यक्रमों के बीच प्रासंगिक अंतर mainफ़ंक्शन के असेंबली आउटपुट में नहीं मिलेगा क्योंकि सभी भारी उठाने वाले पर्दे के पीछे होते हैं।


21
संयोग से C रनटाइम को भी सेट करने की आवश्यकता है, और यह एक फ़ंक्शन में होता है जिसे कॉल किया जाता है _startलेकिन इसका कोड C रनटाइम लाइब्रेरी का हिस्सा है। किसी भी दर पर यह C और C ++ दोनों के लिए होता है।
कोनराड रुडोल्फ

2
@Deduplicator: वास्तव में, डिफ़ॉल्ट रूप से iostream लाइब्रेरी कोई बफ़रिंग नहीं करता है std::coutऔर इसके बजाय I / O को stdio कार्यान्वयन (जो अपने स्वयं के बफ़रिंग तंत्र का उपयोग करता है) पास करता है। विशेष रूप से, जब एक इंटरेक्टिव टर्मिनल से जुड़ा हुआ है (क्या जाना जाता है), तो डिफ़ॉल्ट रूप से आपको लिखते समय कभी भी पूरी तरह से बफर आउटपुट दिखाई नहीं देगा std::cout। यदि आप iostream लाइब्रेरी के लिए अपने स्वयं के बफरिंग तंत्र का उपयोग करना चाहते हैं, तो आपको स्पष्ट रूप से stdio के साथ सिंक्रनाइज़ेशन को अक्षम करना होगा std::cout

6
@KonradRudolph: वास्तव में, printfयहां धाराओं को प्रवाहित करने की आवश्यकता नहीं है। वास्तव में, एक सामान्य उपयोग के मामले में (आउटपुट को फ़ाइल में रीडायरेक्ट किया जाता है), आप आमतौर पर पाएंगे कि printfस्टेटमेंट फ्लश नहीं होता है। केवल जब आउटपुट लाइन-बफ़र्ड या अनबफ़र्ड होता है, तो printfएक फ्लश ट्रिगर होगा ।

2
@PeterCordes: ठीक है, आप अप्रभावित आउटपुट बफ़र्स के साथ ब्लॉक नहीं कर सकते हैं, लेकिन आप आश्चर्य में दौड़ सकते हैं जहां कार्यक्रम ने आपके इनपुट को स्वीकार कर लिया है और अपेक्षित आउटपुट प्रदर्शित किए बिना मार्च किया है। मुझे यह पता है क्योंकि मैंने एक "मदद करने के लिए अवसर दिया है, मेरा कार्यक्रम इनपुट के दौरान लटका हुआ है, लेकिन मैं इसका पता नहीं लगा सकता!" जिसने कुछ दिनों के लिए एक और डेवलपर फिट दिया था।

2
@PeterCordes: मैं जो तर्क देता हूं वह है "आप क्या मतलब लिखते हैं" - जब आप आउटपुट के लिए अंततः उपलब्ध होने का मतलब रखते हैं, तो newlines उपयुक्त होते हैं, और जब आप आउटपुट तुरंत उपलब्ध होने का मतलब रखते हैं, तो एंडल उपयुक्त होता है।

53

यह प्रसिद्ध है कि C ++ में आप जो खाते हैं उसके लिए भुगतान करते हैं। तो, इस मामले में, मैं किसके लिए भुगतान कर रहा हूं?

यह आसान है। आप के लिए भुगतान std::cout। "आप केवल वही खाते हैं जो आप खाते हैं" का अर्थ यह नहीं है "आपको हमेशा सर्वोत्तम मूल्य मिलते हैं"। यकीन है, printfसस्ता है। कोई यह तर्क दे सकता है कि std::coutसुरक्षित और अधिक बहुमुखी है, इस प्रकार इसकी अधिक लागत उचित है (यह अधिक लागत देता है, लेकिन अधिक मूल्य प्रदान करता है), लेकिन यह बात याद आती है। आप उपयोग नहीं करते हैं printf, आप उपयोग करते हैं std::cout, इसलिए आप उपयोग करने के लिए भुगतान करते हैं std::cout। आप उपयोग करने के लिए भुगतान नहीं करते हैं printf

एक अच्छा उदाहरण आभासी कार्य है। वर्चुअल फ़ंक्शंस में कुछ रनटाइम लागत और स्थान की आवश्यकताएं होती हैं - लेकिन केवल अगर आप वास्तव में उनका उपयोग करते हैं। यदि आप आभासी कार्यों का उपयोग नहीं करते हैं, तो आप कुछ भी भुगतान नहीं करते हैं।

कुछ टिप्पणी

  1. भले ही C ++ कोड अधिक विधानसभा निर्देशों का मूल्यांकन करता है, यह अभी भी निर्देशों का एक मुट्ठी भर है, और किसी भी प्रदर्शन ओवरहेड को अभी भी वास्तविक I / O संचालन द्वारा बौना होने की संभावना है।

  2. दरअसल, कभी-कभी यह "C ++ में आप जो खाते हैं उसके लिए भुगतान करते हैं" से भी बेहतर है। उदाहरण के लिए, कंपाइलर यह कह सकता है कि वर्चुअल फ़ंक्शन कॉल की कुछ परिस्थितियों में आवश्यकता नहीं है, और इसे गैर-वर्चुअल कॉल में बदल सकते हैं। इसका मतलब है कि आपको मुफ्त में वर्चुअल फ़ंक्शंस मिल सकते हैं । क्या यह महान नहीं है?


6
आपको मुफ्त में वर्चुअल फ़ंक्शंस नहीं मिलते हैं। आपको अभी भी उन्हें पहले लिखने की लागत का भुगतान करना होगा, और फिर अपने कोड के संकलक के परिवर्तन को डीबग करना होगा जब यह आपके विचार से मेल नहीं खाता कि यह क्या करना चाहिए था।
एलिफ़ेरो

2
@alephzero मुझे यकीन नहीं है कि प्रदर्शन लागत के साथ विकास लागतों की तुलना करना विशेष रूप से प्रासंगिक है।

एक सज़ा बर्बाद करने का इतना बड़ा मौका ... आप 'मूल्य' के बजाय 'कैलोरी' शब्द का इस्तेमाल कर सकते थे। इससे आप कह सकते हैं कि C ++, C से कम या कम से कम है ... प्रश्न में विशिष्ट कोड (C के पक्ष में C ++ के खिलाफ पक्षपाती हूं इसलिए मैं काफी आगे नहीं जा सकता)। अफसोस। @ बेलकोकिया यह सभी मामलों में प्रासंगिक नहीं हो सकता है, लेकिन यह निश्चित रूप से कुछ है जिसे अवहेलना नहीं करना चाहिए। इस प्रकार यह पूरे पर प्रासंगिक है।
प्रिएफ्टन

46

प्रिंटफ के लिए "असेंबली लिस्टिंग" प्रिंटफ के लिए नहीं है, लेकिन पुट (संकलक अनुकूलन के लिए?) के लिए है। प्रिंटफ़ पुट की तुलना में बहुत अधिक जटिल है ... मत भूलना!


13
यह अब तक का सबसे अच्छा जवाब है, क्योंकि बाकी सभी लोग लाल रंग के हेरिंग पर लटकाए गए std::coutहैं, जो विधानसभा सूची में दिखाई नहीं दे रहे हैं।
कोनराड रूडोल्फ

12
असेंबली लिस्टिंग एक कॉल के लिए है puts , जो कॉल के समान दिखता है printfयदि आप केवल एक प्रारूप स्ट्रिंग और शून्य अतिरिक्त आर्गन पास करते हैं। (सिवाय इसके कि वहाँ भी होगा xor %eax,%eaxक्योंकि हम शून्य एफपी आर्ग्स को एक वैरेडिक फ़ंक्शन में रजिस्टर कर रहे हैं।) इनमें से कुछ भी कार्यान्वयन नहीं हैं, बस एक सूचक को स्ट्रिंग से लाइब्रेरी फ़ंक्शन में पास करना है। लेकिन हाँ, के अनुकूलन printfके लिए putsकुछ जीसीसी प्रारूपों है कि केवल के लिए करता है "%s", या जब कोई रूपांतरण, और एक नई पंक्ति के साथ स्ट्रिंग समाप्त होता है।
पीटर कॉर्ड्स

45

मुझे यहाँ कुछ मान्य उत्तर दिखाई देते हैं, लेकिन मैं विस्तार में थोड़ा और विस्तार करने जा रहा हूँ।

यदि आप पाठ की इस पूरी दीवार से नहीं जाना चाहते हैं तो अपने मुख्य प्रश्न के उत्तर के लिए नीचे दिए गए सारांश पर जाएँ।


मतिहीनता

तो, इस मामले में, मैं किसके लिए भुगतान कर रहा हूं?

आप अमूर्तता के लिए भुगतान कर रहे हैं । सरल और अधिक मानवीय अनुकूल कोड लिखने में सक्षम होने के कारण लागत आती है। C ++ में, जो एक वस्तु-उन्मुख भाषा है, लगभग सब कुछ एक वस्तु है। जब आप किसी वस्तु का उपयोग करते हैं, तो तीन मुख्य चीजें हमेशा हुड के नीचे होंगी:

  1. ऑब्जेक्ट निर्माण, मूल रूप से ऑब्जेक्ट और उसके डेटा के लिए मेमोरी आवंटन।
  2. ऑब्जेक्ट आरंभीकरण (आमतौर पर किसी init()विधि के माध्यम से )। आमतौर पर मेमोरी आवंटन इस कदम में पहली चीज के रूप में हुड के तहत होता है।
  3. वस्तु विनाश (हमेशा नहीं)।

आप इसे कोड में नहीं देखते हैं, लेकिन हर बार जब आप किसी वस्तु का उपयोग करते हैं, तो उपरोक्त तीनों चीजों को किसी भी तरह से होना चाहिए। यदि आप मैन्युअल रूप से सब कुछ करना चाहते थे, तो कोड स्पष्ट रूप से लंबा होगा।

अब, ओवरहेड को जोड़े बिना एब्सट्रैक्शन को कुशलता से बनाया जा सकता है: एब्स्ट्रैक्शन के ओवरहेड्स को हटाने के लिए कम्पाइलर इनलाइनिंग और अन्य तकनीकों का उपयोग कंपाइलर और प्रोग्रामर दोनों द्वारा किया जा सकता है, लेकिन यह आपका मामला नहीं है।

C ++ में वास्तव में क्या हो रहा है?

यहाँ यह टूट गया है:

  1. std::ios_baseवर्ग आरंभ नहीं हो जाता है, जो सब कुछ मैं / संबंधित हे के लिए आधार वर्ग है।
  2. std::coutवस्तु आरंभ नहीं हो जाता।
  3. आपकी स्ट्रिंग को लोड किया गया है और पास किया गया है std::__ostream_insert, जो (जैसा कि आप पहले ही नाम से पता लगा चुके हैं) एक विधि है std::cout(मूल रूप से <<ऑपरेटर) जो एक स्ट्रिंग को धारा में जोड़ता है।
  4. cout::endlको भी पास किया गया है std::__ostream_insert
  5. __std_dso_handleको पारित किया जाता है __cxa_atexit, जो एक वैश्विक कार्य है जो कार्यक्रम से बाहर निकलने से पहले "सफाई" के लिए जिम्मेदार है। __std_dso_handleस्वयं को इस कार्य द्वारा शेष वैश्विक वस्तुओं को नष्ट करने और नष्ट करने के लिए कहा जाता है।

तो C == का उपयोग करके कुछ भी भुगतान नहीं किया जा रहा है?

C कोड में, बहुत कम चरण हो रहे हैं:

  1. आपका स्ट्रिंग लोड हो गया है और रजिस्टर के putsमाध्यम से पारित हो गया है edi
  2. puts कहा जाता है।

कहीं भी कोई वस्तु नहीं, इसलिए किसी भी चीज़ को आरम्भ करने / नष्ट करने की आवश्यकता नहीं है।

हालांकि इसका मतलब यह नहीं है कि आप सी में कुछ भी "भुगतान" नहीं कर रहे हैं । आप अभी भी अमूर्तता के लिए भुगतान कर रहे हैं, और सी मानक लाइब्रेरी और डायनामिक रिज़ॉल्यूशन के printfफ़ंक्शन (या, वास्तव में puts, जो संकलक द्वारा अनुकूलित किया गया है, क्योंकि आपको किसी भी प्रारूप स्ट्रिंग की आवश्यकता नहीं है) अभी भी हुड के तहत होता है।

यदि आप इस कार्यक्रम को शुद्ध सभा में लिखते हैं तो यह कुछ इस तरह दिखाई देगा:

jmp start

msg db "Hello world\n"

start:
    mov rdi, 1
    mov rsi, offset msg
    mov rdx, 11
    mov rax, 1          ; write
    syscall
    xor rdi, rdi
    mov rax, 60         ; exit
    syscall

जो मूल रूप से केवल write syscall के बाद syscall को लागू करने में परिणत होता है exit। अब यह न्यूनतम इसी कार्य को पूरा करने के लिए किया जाएगा।


संक्षेप में

सी अधिक नंगे हड्डी है , और केवल नंगे न्यूनतम की आवश्यकता होती है, जो उपयोगकर्ता को पूर्ण नियंत्रण छोड़ती है, जो मूल रूप से वे चाहते हैं कि पूरी तरह से अनुकूलित और अनुकूलित करने में सक्षम हैं। आप प्रोसेसर को एक रजिस्टर में एक स्ट्रिंग लोड करने के लिए कहते हैं और फिर उस स्ट्रिंग का उपयोग करने के लिए एक लाइब्रेरी फ़ंक्शन को कॉल करते हैं। दूसरी ओर C ++ अधिक जटिल और सार है । जटिल कोड लिखते समय इसका बहुत फायदा होता है, और आसानी से लिखने और अधिक मानवीय अनुकूल कोड की अनुमति देता है, लेकिन यह स्पष्ट रूप से एक लागत पर आता है। C ++ में हमेशा प्रदर्शन में एक खामी होने वाली है, अगर C की तुलना इस तरह के मामलों में की जाती है, क्योंकि C ++ ऐसे बुनियादी कार्यों को पूरा करने के लिए जो आवश्यक है उससे अधिक प्रदान करता है, और इस प्रकार यह अधिक ओवरहेड जोड़ता है

आपके मुख्य प्रश्न का उत्तर देना :

क्या मैं उसके लिए भुगतान कर रहा हूं जो मैं नहीं खा रहा हूं?

इस विशिष्ट मामले में, हाँ । आप ऐसी किसी भी चीज़ का लाभ नहीं उठा रहे हैं जो C ++ को C से अधिक की पेशकश करनी है, लेकिन ऐसा सिर्फ इसलिए है क्योंकि कोड के उस सरल टुकड़े में कुछ भी नहीं है जो C ++ आपकी मदद कर सकता है: यह इतना सरल है कि आपको वास्तव में C ++ की आवश्यकता नहीं है।


ओह, और बस एक और बात!

सी ++ के फायदे पहली नज़र में स्पष्ट नहीं लग सकते हैं, क्योंकि आपने एक बहुत ही सरल और छोटा कार्यक्रम लिखा है, लेकिन थोड़ा और अधिक जटिल उदाहरण देखें और अंतर देखें (दोनों प्रोग्राम सटीक एक ही काम करते हैं):

सी :

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    return *(int*)a - *(int*)b;
}

int main(void) {
    int i, n, *arr;

    printf("How many integers do you want to input? ");
    scanf("%d", &n);

    arr = malloc(sizeof(int) * n);

    for (i = 0; i < n; i++) {
        printf("Index %d: ", i);
        scanf("%d", &arr[i]);
    }

    qsort(arr, n, sizeof(int), cmp)

    puts("Here are your numbers, ordered:");

    for (i = 0; i < n; i++)
        printf("%d\n", arr[i]);

    free(arr);

    return 0;
}

C ++ :

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(void) {
    int n;

    cout << "How many integers do you want to input? ";
    cin >> n;

    vector<int> vec(n);

    for (int i = 0; i < vec.size(); i++) {
        cout << "Index " << i << ": ";
        cin >> vec[i];
    }

    sort(vec.begin(), vec.end());

    cout << "Here are your numbers:" << endl;

    for (int item : vec)
        cout << item << endl;

    return 0;
}

उम्मीद है कि आप स्पष्ट रूप से देख सकते हैं कि मेरा क्या मतलब है। यह भी देखें कि C का उपयोग करके आपको निम्न स्तर पर मेमोरी कैसे प्रबंधित करनी है mallocऔर freeआपको अनुक्रमण और आकारों के बारे में अधिक सावधानी बरतने की आवश्यकता है, और इनपुट और प्रिंटिंग लेते समय आपको किस तरह से विशिष्ट होना चाहिए।


27

शुरू करने के लिए कुछ गलत धारणाएं हैं। सबसे पहले, C ++ प्रोग्राम में 22 निर्देशों का परिणाम नहीं है , यह उनमें से 22,000 से अधिक है (मैंने अपनी टोपी से उस संख्या को खींच लिया, लेकिन यह बॉलपार्क में लगभग है)। इसके अलावा, सी कोड 9 निर्देशों में परिणाम नहीं करता है , या तो। वे केवल वे हैं जिन्हें आप देखते हैं।

सी कोड क्या है, बहुत सारे सामान करने के बाद जो आपको दिखाई नहीं देता है, यह सीआरटी से एक फ़ंक्शन को कॉल करता है (जो आमतौर पर साझा नहीं किया जाता है, लेकिन आवश्यक रूप से मौजूद शेयर के रूप में मौजूद है), फिर रिटर्न वैल्यू या हैंडल की जांच नहीं करता है त्रुटियों, और बाहर घंटी। संकलक और अनुकूलन सेटिंग्स तो यह और भी वास्तव में फोन नहीं करता है पर निर्भर करता है printfलेकिन puts, या और भी अधिक आदिम कुछ।
आप C ++ में भी कमोबेश एक ही प्रोग्राम (कुछ अदृश्य इनिट फंक्शन्स को छोड़कर) लिख सकते थे, अगर आप केवल उसी फंक्शन को उसी तरह कहते थे। या, यदि आप सुपर-सही होना चाहते हैं, तो वही फ़ंक्शन उपसर्ग करता है std::

संबंधित C ++ कोड वास्तव में सभी समान चीजों पर नहीं है। जबकि यह पूरी <iostream>तरह से एक मोटा बदसूरत सुअर होने के लिए अच्छी तरह से जाना जाता है जो छोटे कार्यक्रमों के लिए एक विशाल उपरि जोड़ता है (एक "वास्तविक" कार्यक्रम में आप वास्तव में इतना ध्यान नहीं देते हैं), कुछ हद तक उचित व्याख्या यह है कि यह एक भयानक है बहुत सारा सामान जो आप नहीं देखते हैं और जो सिर्फ काम करता है । सहित, लेकिन विभिन्न संख्या प्रारूपों और स्थानों और whatnot, और बफरिंग, और उचित त्रुटि से निपटने सहित बहुत अधिक किसी भी सामान की जादुई स्वरूपण तक सीमित नहीं है। गलती संभालना? ठीक है, लगता है कि, स्ट्रिंग को आउटपुट करना वास्तव में विफल हो सकता है, और सी प्रोग्राम के विपरीत, सी ++ प्रोग्राम होगा इस चुपचाप की अनदेखी नहीं । क्या माना जा रहा हैstd::ostreamहुड के तहत करता है, और किसी के बारे में पता किए बिना, यह वास्तव में बहुत हल्का है। ऐसा नहीं है कि मैं इसका उपयोग कर रहा हूं क्योंकि मैं एक जुनून के साथ स्ट्रीम सिंटैक्स से नफरत करता हूं। लेकिन फिर भी, यह बहुत बढ़िया है यदि आप विचार करते हैं कि यह क्या करता है।

लेकिन निश्चित रूप से, C ++ कुल मिलाकर उतना कुशल नहीं है जितना C हो सकता है। यह उतना कुशल नहीं हो सकता क्योंकि यह एक ही चीज नहीं है और यह एक ही काम नहीं कर रहा है। यदि और कुछ नहीं, C ++ अपवाद उत्पन्न करता है (और उन पर उत्पन्न, संभाल या विफल होने के लिए कोड) और यह कुछ गारंटी देता है जो C नहीं देता है। इसलिए, निश्चित रूप से, C ++ प्रोग्राम थोड़े को थोड़ा बड़ा होने की आवश्यकता है। बड़ी तस्वीर में, हालांकि, यह किसी भी तरह से मायने नहीं रखता है। इसके विपरीत, असली के लिए कार्यक्रमों के लिए, मैंने शायद ही कभी C ++ को बेहतर प्रदर्शन करते पाया है क्योंकि एक या किसी अन्य कारण से, यह अधिक अनुकूल अनुकूलन के लिए उधार देने लगता है। विशेष रूप से मुझसे क्यों न पूछें, मुझे नहीं पता होगा।

यदि, आग-और-भूल-की-आशा के लिए-के बजाय सबसे अच्छा आप सी कोड लिखने के लिए परवाह करते हैं जो सही है (यानी आप वास्तव में त्रुटियों की जांच करते हैं, और कार्यक्रम त्रुटियों की उपस्थिति में सही ढंग से व्यवहार करता है) तो अंतर सीमांत है, अगर मौजूद है।


16
बहुत अच्छा जवाब, सिवाय इसके कि इस जोर: "लेकिन यकीन है, सी ++ कुल मिलाकर उतना कुशल नहीं है जितना कि सी हो सकता है" बस गलत है। C ++ C के समान कुशल हो सकता है, और समतुल्य उच्च-स्तरीय कोड समकक्ष C कोड से अधिक कुशल हो सकता है। हां, C ++ में अपवादों को संभालने के कारण कुछ ओवरहेड हैं, लेकिन आधुनिक कंपाइलरों पर बेहतर लागत-रहित सार से प्रदर्शन लाभ की तुलना में इसका ओवरहेड नगण्य है।
कोनराड रुडोल्फ

अगर मुझे सही तरीके से समझ में आता है, तो क्या std::coutअपवाद भी फेंकता है?
Saher

6
@ शायर: हाँ, नहीं, हो सकता है। std::coutएक std::basic_ostreamऔर है कि एक कर सकते हैं फेंक, और यह कर सकते हैं अन्यथा होने वाले अपवाद rethrow यदि कॉन्फ़िगर किया गया ऐसा करने के लिए या यह कर सकते हैं अपवाद निगल। बात यह है कि सामान विफल हो सकता है, और C ++ के साथ-साथ C ++ मानक लीब (ज्यादातर) निर्मित है इसलिए असफलता आसानी से किसी का ध्यान नहीं जाती है। यह एक झुंझलाहट और आशीर्वाद है (लेकिन, झुंझलाहट से अधिक आशीर्वाद)। दूसरी ओर C सिर्फ आपको मध्यमा उंगली दिखाता है। आप एक रिटर्न कोड की जाँच नहीं करते, आप कभी नहीं जानते कि क्या हुआ था।
डेमोन

1
@KonradRudolph: सच है, यह वही है जो मैं "मैं शायद ही कभी C ++ बेहतर प्रदर्शन कर पाया हूं क्योंकि एक या किसी अन्य कारण से, यह अधिक अनुकूल अनुकूलन के लिए उधार देने के लिए लगता है। मुझे विशेष रूप से क्यों नहीं पूछें"। । यह तुरंत स्पष्ट नहीं है कि क्यों, लेकिन शायद ही कभी यह बेहतर अनुकूलन करता है। जो कोई भी कारण के लिए। आपको लगता है कि यह सभी ऑप्टिमाइज़र के लिए समान है, लेकिन ऐसा नहीं है।
डेमन

22

आप गलती के लिए भुगतान कर रहे हैं। 80 के दशक में, जब कंपाइलर प्रारूप स्ट्रिंग्स की जांच करने के लिए पर्याप्त नहीं थे, तो ऑपरेटर ओवरलोडिंग को io के दौरान प्रकार सुरक्षा के कुछ समानता को लागू करने के लिए एक अच्छा तरीका के रूप में देखा गया था। हालाँकि, इसके हर एक बैनर फ़ीचर को या तो बुरी तरह से या वैचारिक रूप से शुरू से ही दिवालिया कर दिया गया है:

<Iomanip>

C ++ स्ट्रीम io api का सबसे बड़ा हिस्सा इस फॉर्मेटिंग हेडर लाइब्रेरी का अस्तित्व है। स्टेटफुल और बदसूरत और त्रुटि प्रवण होने के अलावा, यह जोड़े को स्ट्रीम के लिए स्वरूपण करते हैं।

मान लीजिए कि आप 8 अंक शून्य भरे हुए हेक्स अहस्ताक्षरित के साथ एक लाइन प्रिंट करना चाहते हैं, जिसके बाद 3 दशमलव स्थानों के साथ एक डबल स्थान है। इसके साथ <cstdio>, आपको एक संक्षिप्त प्रारूप स्ट्रिंग पढ़ने को मिलता है। इसके साथ <ostream>, आपको पुरानी स्थिति को सहेजना होगा, संरेखण को दाईं ओर सेट करना होगा, भरण वर्ण सेट करना होगा, चौड़ाई भरना होगा, बेस को हेक्स पर सेट करना होगा, पूर्णांक को आउटपुट करना होगा, सहेजे गए राज्य को पुनर्स्थापित करना होगा (अन्यथा आपका पूर्णांक स्वरूपण आपके फ्लोट स्वरूपण को प्रदूषित कर देगा), स्थान का उत्पादन , निर्धारित करने के लिए संकेतन, सटीक सेट, डबल और न्यूलाइन आउटपुट, फिर पुराने स्वरूपण को पुनर्स्थापित करें।

// <cstdio>
std::printf( "%08x %.3lf\n", ival, fval );

// <ostream> & <iomanip>
std::ios old_fmt {nullptr};
old_fmt.copyfmt (std::cout);
std::cout << std::right << std::setfill('0') << std::setw(8) << std::hex << ival;
std::cout.copyfmt (old_fmt);
std::cout << " " << std::fixed << std::setprecision(3) << fval << "\n";
std::cout.copyfmt (old_fmt);

ऑपरेटर ओवरलोडिंग

<iostream> ऑपरेटर ओवरलोडिंग का उपयोग न करने का पोस्टर बच्चा है:

std::cout << 2 << 3 && 0 << 5;

प्रदर्शन

std::coutकई बार धीमा होता है printf()। बड़े पैमाने पर करतब और आभासी प्रेषण अपने टोल लेता है।

धागा सुरक्षा

दोनों <cstdio>और <iostream>थ्रेड सुरक्षित हैं कि हर फ़ंक्शन कॉल परमाणु है। लेकिन, printf()प्रति कॉल बहुत कुछ किया जाता है। यदि आप <cstdio>विकल्प के साथ निम्नलिखित प्रोग्राम चलाते हैं , तो आपको केवल एक पंक्ति दिखाई देगी f। यदि आप <iostream>एक मल्टीकोर मशीन पर उपयोग करते हैं, तो आप संभवतः कुछ और देखेंगे।

// g++ -Wall -Wextra -Wpedantic -pthread -std=c++17 cout.test.cpp

#define USE_STREAM 1
#define REPS 50
#define THREADS 10

#include <thread>
#include <vector>

#if USE_STREAM
    #include <iostream>
#else
    #include <cstdio>
#endif

void task()
{
    for ( int i = 0; i < REPS; ++i )
#if USE_STREAM
        std::cout << std::hex << 15 << std::dec;
#else
        std::printf ( "%x", 15);
#endif

}

int main()
{
    auto threads = std::vector<std::thread> {};
    for ( int i = 0; i < THREADS; ++i )
        threads.emplace_back(task);

    for ( auto & t : threads )
        t.join();

#if USE_STREAM
        std::cout << "\n<iostream>\n";
#else
        std::printf ( "\n<cstdio>\n" );
#endif
}

इस उदाहरण का मुंहतोड़ जवाब यह है कि ज्यादातर लोग किसी भी तरह से कई थ्रेड्स से एक भी फाइल डिस्क्रिप्टर पर न लिखने के लिए अनुशासन का इस्तेमाल करते हैं। ठीक है, उस मामले में, आपको यह देखना <iostream>होगा कि प्रत्येक <<और हर पर एक ताला लगाएगा >>। जबकि <cstdio>, आप अक्सर लॉक नहीं करेंगे, और आपके पास लॉकिंग न करने का विकल्प भी होगा।

<iostream> कम सुसंगत परिणाम प्राप्त करने के लिए अधिक तालों का विस्तार करता है।


2
Printf के अधिकांश कार्यान्वयन में स्थानीयकरण के लिए एक अत्यंत उपयोगी विशेषता है: गिने हुए पैरामीटर। यदि आपको दो अलग-अलग भाषाओं (जैसे अंग्रेजी और फ्रेंच) में कुछ आउटपुट का उत्पादन करने की आवश्यकता है और शब्द क्रम अलग है, तो आप एक ही स्वरूपण स्ट्रिंग के साथ एक ही प्रिंटफ़ का उपयोग कर सकते हैं, और यह विभिन्न क्रम में मापदंडों को प्रिंट कर सकता है।
gnasher729

2
धाराओं के स्टेटफुल फॉर्मेटिंग ने बग्स को खोजने के लिए बहुत मुश्किल दिया होगा मुझे नहीं पता कि क्या कहना है। बहुत बढ़िया जवाब। अगर मैं कर सकता तो एक से अधिक बार उत्थान करूंगा।
गणितज्ञ

6
" std::coutकई बार धीमा होता है printf()" - यह दावा पूरे नेट पर दोहराया जाता है लेकिन यह युगों में सच नहीं है। आधुनिक IOstream कार्यान्वयन बराबर के साथ करते हैं printf। उत्तरार्द्ध भी बफर स्ट्रीम और स्थानीय आईओ (ऑपरेटिंग सिस्टम द्वारा किया जाता है लेकिन फिर भी किया जाता है) से निपटने के लिए आंतरिक रूप से आभासी प्रेषण करता है।
कोनराड रुडोल्फ

3
@ केवीएनजेड और यह बहुत अच्छा है, लेकिन यह एक एकल, विशिष्ट कॉल को बेंचमार्किंग कर रहा है, जो एफएमटी की विशिष्ट ताकत (एक ही स्ट्रिंग में विभिन्न स्वरूपों के बहुत सारे) को प्रदर्शित करता है। अधिक विशिष्ट उपयोग में printfऔर coutसिकुड़ने के बीच का अंतर । संयोग से इस साइट पर बहुत सारे ऐसे बेंचमार्क हैं।
कोनराड रुडोल्फ

3
@KonradRudolph यह सच नहीं है। माइक्रोबेन्चार्म्स अक्सर ब्लोट और इनडायरेक्शन की लागत को कम कर देते हैं क्योंकि वे कुछ सीमित संसाधनों को समाप्त नहीं करते हैं (जैसा कि यह रजिस्टर, आईकैश, मेमोरी, शाखा भविष्यवक्ताओं) जहां एक वास्तविक कार्यक्रम होगा। जब आप "अधिक विशिष्ट उपयोग" करने के लिए कहते हैं, तो यह मूल रूप से कह रहा है कि आपके पास कहीं और अधिक ब्लोट है, जो ठीक है, लेकिन विषय से दूर है। मेरी राय में, यदि आपके पास प्रदर्शन आवश्यकताएं नहीं हैं, तो आपको C ++ में प्रोग्राम करने की आवश्यकता नहीं है।
केविन जेड

18

अन्य सभी उत्तरों ने जो कहा है, इसके अलावा,
यह भी तथ्य है कि std::endlजैसा है वैसा नहीं है '\n'

यह दुर्भाग्य से आम गलत धारणा है। std::endl"नई लाइन" का मतलब यह नहीं है,
इसका मतलब है "नई लाइन प्रिंट करें और फिर स्ट्रीम को फ्लश करें "। फ्लशिंग सस्ता नहीं है!

पूरी तरह से के बीच मतभेद की अनदेखी printfऔर std::coutएक पल के लिए, कार्यात्मक अपने सी उदाहरण के लिए eqvuialent जाए, तो अपनी सी ++ उदाहरण कुछ ऐसा नज़र चाहिए:

#include <iostream>

int main()
{
    std::cout << "Hello world\n";
    return 0;
}

और यहाँ एक उदाहरण है कि आपके उदाहरण क्या होने चाहिए जैसे कि आप निस्तब्धता को शामिल करते हैं।

सी

#include <stdio.h>

int main()
{
    printf("Hello world\n");
    fflush(stdout);
    return 0;
}

सी ++

#include <iostream>

int main()
{
    std::cout << "Hello world\n";
    std::cout << std::flush;
    return 0;
}

कोड की तुलना करते समय, आपको हमेशा सावधान रहना चाहिए कि आप इस तरह की तुलना कर रहे हैं और आप अपने कोड का क्या कर रहे हैं इसके निहितार्थ को समझते हैं। कभी-कभी सरलतम उदाहरण भी कुछ लोगों द्वारा महसूस किए जाने की तुलना में अधिक जटिल होते हैं।


वास्तव में, का उपयोग कर std::endl रहा है एक लाइन-बफ़र stdio धारा में एक नई पंक्ति लिखने के लिए कार्यात्मक समकक्ष। stdoutविशेष रूप से, इंटरेक्टिव डिवाइस से कनेक्ट होने पर या तो लाइन-बफ़र या असंबद्ध होना आवश्यक है। लिनक्स, मेरा मानना ​​है कि लाइन-बफ़र विकल्प पर जोर देता है।

वास्तव में, iostream लाइब्रेरी में एक लाइन-बफ़र्ड मोड नहीं है ... लाइन-बफ़रिंग के प्रभाव को प्राप्त करने का तरीका std::endlआउटपुट न्यूलाइन्स का उपयोग करने के लिए ठीक है।

@ हर्किल आग्रह? फिर क्या फायदा setvbuf(3)? या क्या आप कहने का अर्थ है कि डिफ़ॉल्ट लाइन बफर है? FYI करें: आम तौर पर सभी फाइलें ब्लॉक बफ़र्ड होती हैं। यदि कोई स्ट्रीम टर्मिनल को संदर्भित करता है (जैसा कि आम तौर पर स्टडआउट करता है), तो यह लाइन बफर है। मानक त्रुटि स्ट्रीम stderr हमेशा डिफ़ॉल्ट रूप से अप्रभावित रहता है।
प्रिएफ्टन

क्या printfएक newline वर्ण का सामना करने पर स्वचालित रूप से फ्लश नहीं होता है?
bool3max

1
@ bool3max यह केवल मुझे बताएगा कि मेरा पर्यावरण क्या करता है, यह अन्य वातावरणों में भिन्न हो सकता है। यहां तक ​​कि अगर यह सभी सबसे लोकप्रिय कार्यान्वयनों में समान व्यवहार करता है, तो इसका मतलब यह नहीं है कि कहीं एक किनारे का मामला है। यही कारण है कि स्टैनर्ड इतना महत्वपूर्ण है - मानक यह निर्धारित करता है कि क्या सभी कार्यान्वयनों के लिए कुछ समान होना चाहिए या क्या कार्यान्वयन के बीच भिन्न होने की अनुमति है या नहीं।
चरण 2

16

हालांकि मौजूदा तकनीकी जवाब सही हैं, मुझे लगता है कि सवाल अंततः इस गलत धारणा से उपजा है:

यह प्रसिद्ध है कि C ++ में आप जो खाते हैं उसके लिए भुगतान करते हैं।

यह C ++ समुदाय से सिर्फ मार्केटिंग की बात है। (निष्पक्ष होने के लिए, हर भाषा समुदाय में विपणन चर्चा है।) इसका कोई ठोस मतलब नहीं है कि आप गंभीरता से इस पर निर्भर हो सकते हैं।

"आप जो आप उपयोग करते हैं उसके लिए भुगतान करते हैं" का अर्थ है कि यदि आप उस सुविधा का उपयोग कर रहे हैं तो C ++ सुविधा केवल ओवरहेड है। लेकिन "एक विशेषता" की परिभाषा असीम रूप से दानेदार नहीं है। अक्सर आप उन सक्रिय विशेषताओं को समाप्त कर देंगे जिनमें कई पहलू होते हैं, और भले ही आपको केवल उन पहलुओं के सबसेट की आवश्यकता हो, यह आंशिक रूप से फीचर को आंशिक रूप से लाने के लिए व्यावहारिक या संभव नहीं है।

सामान्य तौर पर, कई (हालांकि यकीनन सभी नहीं) भाषाएं कुशल होने का प्रयास करती हैं, सफलता की डिग्री बदलती के साथ। C ++ पैमाने पर कहीं है, लेकिन इसके डिज़ाइन के बारे में कुछ विशेष या जादुई नहीं है जो इसे इस लक्ष्य में पूरी तरह से सफल होने की अनुमति देगा।


1
सिर्फ दो चीजें हैं जिनके बारे में आप सोच सकते हैं कि आप किसी ऐसी चीज के लिए भुगतान करते हैं जिसका आप उपयोग नहीं करते हैं: अपवाद और RTTI। और मुझे नहीं लगता कि यह विपणन की बात है; C ++ मूल रूप से एक अधिक शक्तिशाली C है, जो कि "आप जो उपयोग करते हैं उसके लिए भुगतान नहीं करते हैं"।
Rakete1111

2
@ Rakete1111 यह लंबे समय से स्थापित है कि यदि अपवाद नहीं फेंकते हैं, तो वे खर्च नहीं करते हैं। यदि आपका प्रोग्राम लगातार फेंक रहा है, तो इसे फिर से डिज़ाइन किया जाना चाहिए। यदि विफलता की स्थिति आपके नियंत्रण से बाहर है, तो आपको उस स्थिति की जाँच करने के लिए बूल रिटर्निंग सैनीटिटी जाँच करनी चाहिए, जो विधि के गलत होने पर निर्भर करने वाली विधि को कॉल करने से पहले हो।
स्कुलमास्टर

1
@schulmaster: अपवाद डिज़ाइन बाधाओं को तब लागू कर सकते हैं जब C ++ में लिखे गए कोड को अन्य भाषाओं में लिखे गए कोड के साथ सहभागिता करने की आवश्यकता होती है, क्योंकि नियंत्रण के गैर-स्थानीय हस्तांतरण केवल मॉड्यूल में आसानी से काम कर सकते हैं यदि मॉड्यूल एक दूसरे के साथ समन्वय करना जानते हैं।
19 अक्टूबर को सुपरकैट

1
(हालाँकि यकीनन सभी नहीं) भाषाएँ कुशल होने का प्रयास करती हैं । निश्चित रूप से सभी नहीं: गूढ़ प्रोग्रामिंग भाषाएं उपन्यास / दिलचस्प होने का प्रयास करती हैं, कुशल नहीं। esolangs.org । उनमें से कुछ, जैसे ब्रेनफक, प्रसिद्ध रूप से अक्षम हैं। या उदाहरण के लिए, शेक्सपियर प्रोग्रामिंग लैंग्वेज, सभी पूर्णांक प्रिंट करने के लिए 227 बाइट्स न्यूनतम आकार (कोडगोल्फ) । उत्पादन उपयोग के लिए अभिप्रेत भाषाओं में से अधिकांश दक्षता के लिए लक्ष्य रखते हैं, लेकिन कुछ (जैसे बैश) ज्यादातर सुविधा के लिए लक्ष्य रखते हैं और धीमी गति से ज्ञात होते हैं।
पीटर कॉर्ड्स

2
वैसे तो यह मार्केटिंग है लेकिन यह लगभग पूरी तरह से सच है। आप इसमें शामिल हो सकते हैं <cstdio>और शामिल नहीं <iostream>हो सकते, ठीक उसी तरह जैसे आप कैसे संकलित कर सकते हैं -fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables
केवीजेड

11

C ++ में इनपुट / आउटपुट फ़ंक्शन सुरुचिपूर्ण ढंग से लिखे गए हैं और डिज़ाइन किए गए हैं ताकि वे उपयोग करने में सरल हों। कई मामलों में वे C ++ में ऑब्जेक्ट-ओरिएंटेड सुविधाओं के लिए एक शोकेस हैं।

लेकिन आप वास्तव में बदले में थोड़ा सा प्रदर्शन करते हैं, लेकिन निचले स्तर पर कार्यों को संभालने के लिए आपके ऑपरेटिंग सिस्टम द्वारा किए गए समय की तुलना में यह नगण्य है।

आप हमेशा सी शैली के कार्यों में वापस आ सकते हैं क्योंकि वे सी ++ मानक का हिस्सा हैं, या शायद पूरी तरह से पोर्टेबिलिटी छोड़ देते हैं और अपने ऑपरेटिंग सिस्टम पर सीधे कॉल का उपयोग करते हैं।


23
"C ++ में इनपुट / आउटपुट फ़ंक्शंस छिपे हुए राक्षस हैं जो उपयोगिता की एक पतली लिबास के पीछे अपने Cthulian प्रकृति को छिपाने के लिए संघर्ष कर रहे हैं। कई मामलों में वे आधुनिक C ++ कोड को डिज़ाइन नहीं करने के लिए एक शोकेस हैं"। शायद अधिक सटीक होगा।
14:67 पर user673679

3
@ user673679: बहुत सही। C ++ I / O धाराओं के साथ महान मुद्दा यह है कि नीचे क्या है: वास्तव में बहुत अधिक जटिलता चल रही है, और जो कोई भी उनके साथ काम कर रहा है (मैं std::basic_*streamनीचे की ओर उल्लेख कर रहा हूं ) आने वाली eadaches जानता है। वे व्यापक रूप से सामान्य और विरासत के माध्यम से विस्तारित होने के लिए डिज़ाइन किए गए थे; लेकिन किसी ने भी अंततः ऐसा नहीं किया, क्योंकि उनकी जटिलता का कारण है (वहाँ सचमुच की किताबें iostreams पर लिखी गई हैं), इतना है कि नए पुस्तकालयों के लिए पैदा हुए थे बस (जैसे बढ़ावा, ICU आदि)। मुझे संदेह है कि हम कभी भी इस गलती के लिए भुगतान करना बंद कर देंगे।
edmz

1

जैसा कि आपने अन्य उत्तरों में देखा है, आप भुगतान करते हैं जब आप सामान्य पुस्तकालयों में लिंक करते हैं और जटिल रचनाकारों को कॉल करते हैं। यहाँ कोई विशेष सवाल नहीं है, अधिक एक पकड़ है। मैं कुछ वास्तविक दुनिया के पहलुओं की ओर इशारा करता हूँ:

  1. बार्ने का मुख्य डिजाइन सिद्धांत था कि दक्षता को C ++ के बजाय C में बने रहने का एक कारण नहीं माना जा सकता। उस ने कहा, इन क्षमताओं को प्राप्त करने के लिए किसी को सावधान रहने की जरूरत है, और कभी-कभी दक्षताएं होती हैं जो हमेशा काम करती हैं लेकिन सी युक्ति के भीतर 'तकनीकी रूप से' नहीं थीं। उदाहरण के लिए, बिट फ़ील्ड्स का लेआउट वास्तव में निर्दिष्ट नहीं था।

  2. ओस्ट्रीम के माध्यम से देखने की कोशिश करें। ओह माय गॉड फूला हुआ! मैं वहाँ एक उड़ान सिम्युलेटर खोजने के लिए आश्चर्यचकित नहीं होगा। यहां तक ​​कि stdlib के प्रिंटफ () में लगभग 50K रन है। ये आलसी प्रोग्रामर नहीं हैं: प्रिंटफ साइज का आधा हिस्सा अप्रत्यक्ष सटीक तर्कों के साथ करना था जो ज्यादातर लोग कभी उपयोग नहीं करते हैं। लगभग हर वास्तव में बाधित प्रोसेसर की लाइब्रेरी प्रिंटफ के बजाय अपना आउटपुट कोड बनाती है।

  3. आकार में वृद्धि आमतौर पर एक अधिक निहित और लचीला अनुभव प्रदान कर रही है। सादृश्य के रूप में, एक वेंडिंग मशीन कुछ सिक्कों के लिए एक कप कॉफ़ी जैसा पदार्थ बेचेगी और पूरे लेनदेन में एक मिनट का समय लगता है। एक अच्छे रेस्तरां में छोड़ने के लिए एक टेबल सेटिंग शामिल है, बैठा जा रहा है, ऑर्डर कर रहा है, प्रतीक्षा कर रहा है, एक अच्छा कप प्राप्त कर रहा है, बिल प्राप्त कर रहा है, अपनी पसंद के रूपों में भुगतान कर रहा है, एक टिप जोड़ रहा है, और आपके बाहर जाने पर एक अच्छे दिन की कामना की जा रही है। यह एक अलग अनुभव है, और अधिक सुविधाजनक है यदि आप एक जटिल भोजन के लिए दोस्तों के साथ गिर रहे हैं।

  4. लोग अभी भी ANSI C लिखते हैं, हालांकि शायद ही कभी K & R C. मेरा अनुभव है कि हम हमेशा इसे C ++ संकलक के साथ संकलित करते हैं, जो कुछ ड्रैग इन को सीमित करने के लिए ट्वीक का उपयोग करता है। अन्य भाषाओं के लिए अच्छे तर्क हैं: Go बहुपद ओवरहेड और पागल प्रीप्रोसेसर हटाता है। ; होशियार क्षेत्र पैकिंग और मेमोरी लेआउट के लिए कुछ अच्छे तर्क दिए गए हैं। IMHO मुझे लगता है कि किसी भी भाषा के डिज़ाइन को लक्ष्यों की एक सूची के साथ शुरू करना चाहिए, बहुत कुछ पायथन के ज़ेन की तरह ।

यह एक मजेदार चर्चा रही है। आप पूछते हैं कि आपके पास जादुई रूप से छोटे, सरल, सुरुचिपूर्ण, पूर्ण और लचीले पुस्तकालय क्यों नहीं हो सकते हैं?

कोई उत्तर नहीं है। जवाब नहीं होगा। यही उत्तर है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.