इनलाइन चर कैसे काम करते हैं?


124

2016 ओलु आईएसओ आईएसओ सी + + मानकों की बैठक में, इनलाइन वेरिएबल्स नामक एक प्रस्ताव को मानक समिति द्वारा सी ++ 17 में वोट दिया गया था।

आम आदमी की शर्तों में, इनलाइन चर क्या हैं, वे कैसे काम करते हैं और वे किस लिए उपयोगी हैं? इनलाइन चर कैसे घोषित, परिभाषित और उपयोग किए जाने चाहिए?


@jotik मुझे लगता है कि समतुल्य ऑपरेशन वैरिएबल की किसी भी घटना को उसके मूल्य से बदल देगा। आम तौर पर यह केवल तभी मान्य होता है जब चर है const
melpomene

5
यह केवल एक चीज नहीं है जो inlineकीवर्ड फ़ंक्शंस के लिए करता है। inlineकीवर्ड, जब कार्यों के लिए आवेदन किया, एक अन्य महत्वपूर्ण प्रभाव है, जो चर के लिए सीधे तब्दील हो गया है। एक inlineफ़ंक्शन, जिसे संभवतः हेडर फ़ाइल में घोषित किया गया है, लिंक समय पर "डुप्लिकेट प्रतीक" त्रुटियों के परिणामस्वरूप नहीं होगा, भले ही हेडर #includeकई अनुवाद इकाइयों द्वारा डी हो जाए । inlineकीवर्ड, जब चर के लिए आवेदन किया, एक ही सटीक परिणाम होगा। समाप्त।
सैम वार्शविक

4
^ 'अपने कोड की इन-प्लेस कॉपी के साथ इस फ़ंक्शन के लिए किसी भी कॉल को स्थानापन्न' के अर्थ में inline, आशावादी के लिए केवल एक कमजोर, गैर-बाध्यकारी अनुरोध है। कंपाइलर्स अनुरोधित फ़ंक्शन और / या इनलाइन उन लोगों को इनलाइन नहीं करने के लिए स्वतंत्र हैं, जिन्हें आपने एनोटेट नहीं किया था। बल्कि, inlineकीवर्ड का वास्तविक उद्देश्य कई परिभाषा त्रुटियों को दरकिनार करना है।
अंडरस्कोर_ड

जवाबों:


121

प्रस्ताव का पहला वाक्य:

"inline विनिर्देशक चर के रूप में अच्छी तरह के रूप में कार्य करने के लिए लागू किया जा सकता।

inlineफ़ंक्शन में लागू किए गए functionguaranteed प्रभाव , फ़ंक्शन को एकाधिक अनुवाद इकाइयों में बाहरी लिंकेज के साथ, समान रूप से परिभाषित करने की अनुमति देता है। इन-प्रैक्टिस के लिए, जिसका अर्थ है कि हेडर में फ़ंक्शन को परिभाषित करना, जिसे कई अनुवाद इकाइयों में शामिल किया जा सकता है। प्रस्ताव इस संभावना को चरों ओर बढ़ाता है।

तो, व्यावहारिक रूप से (अब स्वीकार किए गए) प्रस्ताव आपको एक हेडर फ़ाइल में inlineबाहरी लिंकेज constनेमस्पेस स्कोप वैरिएबल या किसी भी staticवर्ग डेटा सदस्य को परिभाषित करने के लिए कीवर्ड का उपयोग करने की अनुमति देता है , ताकि उस हेडर को शामिल करते समय परिणामी कई परिभाषाएं दिखाई दें। कई अनुवाद इकाइयां लिंकर के साथ ठीक हैं - यह उनमें से केवल एक को चुनता है।

C ++ 14 तक और इसके लिए आंतरिक मशीनरी इसमें शामिल है, ताकि staticक्लास टेम्प्लेट में चर का समर्थन किया जा सके, लेकिन उस मशीनरी का उपयोग करने का कोई सुविधाजनक तरीका नहीं था। एक जैसे टोटके का सहारा लेना पड़ा

template< class Dummy >
struct Kath_
{
    static std::string const hi;
};

template< class Dummy >
std::string const Kath_<Dummy>::hi = "Zzzzz...";

using Kath = Kath_<void>;    // Allows you to write `Kath::hi`.

C ++ 17 और उसके बाद से मेरा मानना ​​है कि कोई भी लिख सकता है

struct Kath
{
    static std::string const hi;
};

inline std::string const Kath::hi = "Zzzzz...";    // Simpler!

… हैडर फ़ाइल में।

प्रस्ताव में शब्दांकन शामिल है

इनलाइन स्टैटिक डेटा मेंबर को क्लास डेफिनेशन में परिभाषित किया जा सकता है और यह ब्रेस-या-इक्वलाइज़र-इनिशियलाइज़र को pecify कर सकता है। यदि सदस्य को constexprनिर्दिष्टकर्ता के साथ घोषित किया जाता है , तो इसे बिना किसी आरंभक के नामस्थान दायरे में पुन: घोषित किया जा सकता है (यह उपयोग पदावनत है; देखें डीएक्स)। अन्य स्थैतिक डेटा सदस्यों की घोषणा एक ब्रेस-या-इन-इन-इनायलाइज़र निर्दिष्ट नहीं करेगी

… जो ऊपर को और सरल बनाने की अनुमति देता है

struct Kath
{
    static inline std::string const hi = "Zzzzz...";    // Simplest!
};

... जैसा कि टीसी ने इस उत्तर के लिए एक टिप्पणी में दिया है।

इसके अलावा, ​constexprविशेषक inline स्थैतिक डेटा सदस्यों के साथ-साथ कार्यों के लिए भी  निर्दिष्ट  करता है।


नोट्स::
किसी फंक्शन के लिए inlineऑप्टिमाइज़ेशन के बारे में एक संकेत भी होता है, कि कंपाइलर को फंक्शन के मशीन कोड के डायरेक्ट प्रतिस्थापन के साथ इस फंक्शन की कॉल को बदलना पसंद करना चाहिए। इस संकेत को नजरअंदाज किया जा सकता है।


2
साथ ही, प्रतिबंध प्रतिबंध केवल नेमस्पेस स्कोप वैरिएबल पर लागू होता है। क्लास-स्कोप वाले (जैसे Kath::hi) कांस्टेबल होना जरूरी नहीं है।
टीसी

4
नई रिपोर्टों से संकेत मिलता है कि constप्रतिबंध पूरी तरह से हटा दिया गया है।
TC

2
@ निक: चूंकि रिचर्ड स्मिथ (वर्तमान सी ++ समिति "प्रोजेक्ट एडिटर") दो लेखकों में से एक हैं, और चूंकि वह "क्लैंग सी ++ फ्रंटेंड के कोड मालिक" हैं, इसलिए उन्होंने क्लैंग का अनुमान लगाया। और निर्माण गॉडबोल्ट पर 3.9.0 क्लेंग के साथ संकलित किया गया । यह चेतावनी देता है कि इनलाइन चर एक C ++ 1z एक्सटेंशन हैं। मुझे स्रोत और संकलक की पसंद और विकल्पों को साझा करने का कोई तरीका नहीं मिला, इसलिए लिंक केवल सामान्य रूप से साइट पर है, क्षमा करें।
चीयर्स एंड हीथ। - अल्फ

1
कक्षा / संरचना घोषणा के अंदर इनलाइन कीवर्ड की आवश्यकता क्यों है? बस अनुमति क्यों नहीं static std::string const hi = "Zzzzz...";?
sasha.sochka

2
@EmilianCioca: नहीं, आप स्थैतिक आरंभीकरण क्रम के उपद्रव से बच जाएंगे । एक सिंगलटन अनिवार्य रूप से उस से बचने के लिए एक उपकरण है।
चीयर्स एंड हीथ। - अल्फ

15

इनलाइन चर इनलाइन कार्यों के समान हैं। यह लिंकर को संकेत देता है कि चर का केवल एक उदाहरण मौजूद होना चाहिए, भले ही चर को कई संकलन इकाइयों में देखा जाए। लिंकर को यह सुनिश्चित करने की आवश्यकता है कि कोई और प्रतियां नहीं बनाई गई हैं।

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

उदाहरण के लिए, एक इनलाइन फ़ंक्शन के साथ मेयर्स सिंगलटन का उपयोग करने के लिए एक समाधान है :

inline T& instance()
{
  static T global;
  return global;
}

इस दृष्टिकोण के साथ कुछ कमियां हैं, ज्यादातर प्रदर्शन के मामले में। यह ओवरहेड टेंपरेचर सॉल्यूशंस से बचा जा सकता है, लेकिन उन्हें गलत करना आसान है।

इनलाइन चरों के साथ, आप सीधे इसे घोषित कर सकते हैं (बिना एकाधिक परिभाषा लिंकर त्रुटि के)

inline T global;

हेडर केवल पुस्तकालयों के अलावा, ऐसे अन्य मामले हैं जहां इनलाइन चर मदद कर सकते हैं। Nir Friedman CppCon में अपनी चर्चा में इस विषय को शामिल करते हैं: C ++ डेवलपर्स को ग्लोबल्स (और लिंकर) के बारे में क्या जानना चाहिए । इनलाइन वैरिएबल और वर्कअराउंड के बारे में भाग 18m9s से शुरू होता है

लंबी कहानी छोटी है, अगर आपको संकलन इकाइयों के बीच साझा किए जाने वाले वैश्विक चर घोषित करने की आवश्यकता है, तो हेडर फ़ाइल में इनलाइन चर के रूप में घोषित करना सीधा है और पूर्व-सी ++ 17 वर्कअराउंड के साथ समस्याओं से बचा जाता है।

(उदाहरण के लिए, मेयर्स सिंगलटन के लिए अभी भी उपयोग के मामले हैं, यदि आप स्पष्ट रूप से आलसी आरंभीकरण चाहते हैं।)


11

न्यूनतम रननीय उदाहरण

यह भयानक C ++ 17 फीचर हमें इसकी अनुमति देता है:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline constexpr int notmain_i = 42;

const int* notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

const int* notmain_func() {
    return &notmain_i;
}

संकलित करें और चलाएं:

g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main

गिटहब ऊपर

यह भी देखें: इनलाइन चर कैसे काम करते हैं?

इनलाइन चरों पर C ++ मानक

C ++ मानक गारंटी देता है कि पते समान होंगे। C ++ 17 N4659 मानक मसौदा 10.1.6 "इनलाइन विनिर्देशक":

6 बाहरी लिंकेज के साथ एक इनलाइन फ़ंक्शन या चर सभी अनुवाद इकाइयों में एक ही पता होगा।

cppreference https://en.cppreference.com/w/cpp/language/inline बताता है कि अगर staticनहीं दिया गया है, तो इसमें बाहरी लिंकेज है।

जीसीसी इनलाइन चर कार्यान्वयन

हम यह देख सकते हैं कि इसे किस प्रकार लागू किया जाता है:

nm main.o notmain.o

जिसमें है:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
                 U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
                 U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i

notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i

और के man nmबारे में कहते हैं u:

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

इसलिए हम देखते हैं कि इसके लिए एक समर्पित ईएलएफ एक्सटेंशन है।

प्री-सी ++ 17: extern const

C ++ 17 से पहले, और C में, हम एक के साथ एक बहुत ही समान प्रभाव प्राप्त कर सकते हैं extern const, जिससे एकल मेमोरी लोकेशन का उपयोग किया जा सकेगा।

नीचे की ओर inlineहैं:

  • constexprइस तकनीक के साथ वैरिएबल बनाना संभव नहीं है , केवल यह inlineअनुमति देता है: कॉन्स्ट्रेक्ट एक्सटर्नल कैसे घोषित करें?
  • यह कम सुरुचिपूर्ण है क्योंकि आपको हेडर और सीपीपी फ़ाइल में अलग से चर को घोषित करना और परिभाषित करना है

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.cpp

#include "notmain.hpp"

const int notmain_i = 42;

const int* notmain_func() {
    return &notmain_i;
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

extern const int notmain_i;

const int* notmain_func();

#endif

गिटहब ऊपर

प्री-सी ++ 17 हेडर केवल विकल्प

ये externसमाधान के रूप में अच्छे नहीं हैं, लेकिन वे काम करते हैं और केवल एक ही मेमोरी स्थान लेते हैं:

एक constexprफ़ंक्शन, क्योंकि constexprइसका तात्पर्य inlineinline प्रत्येक अनुवाद इकाई पर दिखने वाली परिभाषा (बलों) से है और अनुमति देता है :

constexpr int shared_inline_constexpr() { return 42; }

और मैं शर्त लगाता हूं कि किसी भी सभ्य संकलक कॉल को इनलाइन करेगा।

आप निम्न के रूप में constया constexprस्थिर पूर्णांक चर का भी उपयोग कर सकते हैं :

#include <iostream>

struct MyClass {
    static constexpr int i = 42;
};

int main() {
    std::cout << MyClass::i << std::endl;
    // undefined reference to `MyClass::i'
    //std::cout << &MyClass::i << std::endl;
}

लेकिन आप इसका पता लेने जैसी चीजें नहीं कर सकते हैं, या फिर यह ओड-यूज़ हो जाता है, यह भी देखें: https://en.cppreference.com/w/cpp/language/static "लगातार स्थैतिक सदस्य" और स्थिर स्थैतिक डेटा को परिभाषित करना सदस्यों

सी

C में स्थिति C ++ पूर्व C ++ 17 जैसी ही है, मैंने इस पर एक उदाहरण अपलोड किया है: C में "स्थिर" का क्या अर्थ है?

फर्क सिर्फ इतना है कि C ++, है constतात्पर्य staticवैश्विक के लिए, लेकिन यह सी में नहीं करता है: बनाम `` const` स्थिर const` की सी ++ अर्थ विज्ञान

इसे पूरी तरह से इनलाइन करने का कोई तरीका?

TODO: क्या किसी भी मेमोरी का उपयोग किए बिना, चर को पूरी तरह से इनलाइन करने का कोई तरीका है?

प्रीप्रोसेसर क्या पसंद करता है।

इसके लिए किसी तरह की आवश्यकता होगी:

  • यदि चर का पता लिया जाए तो मना करना या पता लगाना
  • उस जानकारी को ELF ऑब्जेक्ट फ़ाइलों में जोड़ें, और LTO को इसे ऑप्टिमाइज़ करने दें

सम्बंधित:

उबंटू 18.10, जीसीसी 8.2.0 में परीक्षण किया गया।


2
inlineकेवल शब्द के बावजूद, न तो कार्यों के लिए, न ही कार्यों के लिए और न ही चर के लिए लगभग कुछ भी नहीं है। inlineसंकलक को इनलाइन कुछ भी नहीं बताता है। यह लिंकर को यह सुनिश्चित करने के लिए कहता है कि केवल एक ही परिभाषा है, जो परंपरागत रूप से प्रोग्रामर का काम है। तो "इसे पूरी तरह से इनलाइन करने का कोई तरीका?" कम से कम पूरी तरह से असंबंधित प्रश्न है।
एक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.