ইনলাইন ভেরিয়েবলগুলি কীভাবে কাজ করে?


124

২০১ O সালের ওলু আইএসও সি ++ স্ট্যান্ডার্ডস সভায়, ইনলাইন ভেরিয়েবলস নামে একটি প্রস্তাব মান কমিটি দ্বারা সি ++ 17 এ ভোট দেওয়া হয়েছিল।

সাধারণ ব্যক্তির ভাষায়, ইনলাইন ভেরিয়েবলগুলি কী কী, তারা কীভাবে কাজ করে এবং এগুলি কীসের জন্য দরকারী? কীভাবে ইনলাইন ভেরিয়েবলগুলি ঘোষিত, সংজ্ঞায়িত এবং ব্যবহার করা উচিত?


@ জোটিক আমার ধারণা, সমমানের অপারেশনটি ভেরিয়েবলের যে কোনও ঘটনাকে এর মান দ্বারা প্রতিস্থাপন করবে। সাধারণত এটি কেবল বৈধ হয় যদি পরিবর্তনশীল হয় const
মেলম্পোনে

5
মূল inlineশব্দটি ফাংশনগুলির জন্য কেবল এটিই করে না । inlineশব্দ যখন ফাংশন প্রয়োগ, অন্য একটি গুরুত্বপূর্ণ প্রভাব, যা ভেরিয়েবল সরাসরি অনুবাদ করে হয়েছে। একটি inlineফাংশন, সম্ভবতঃ একটি শিরোলেখ ফাইলটিতে এটি ঘোষিত হয়েছে, লিঙ্ক সময়ে "সদৃশ প্রতীক" ত্রুটিগুলির ফলাফল করবে না, এমনকি যদি #includeএকাধিক অনুবাদ ইউনিট দ্বারা শিরোনামটি ডি হয়ে যায়। মূল inlineশব্দটি, যখন ভেরিয়েবলগুলিতে প্রয়োগ করা হয়, ঠিক একই ফলাফল হবে। শেষ।
স্যাম বর্ষাচিক

4
The 'এই ফাংশনের যে কোনও কলকে তার কোডের inlineএকটি অন্তর্নিহিত অনুলিপি সহ বিকল্প কল্পনা' অর্থে, এটি অপটিমাইজারের কাছে কেবল একটি দুর্বল, নন-বাধ্যতামূলক অনুরোধ। সংযোজনকারীরা অনুরোধ করা ফাংশনগুলিকে ইনলাইন না করতে এবং / অথবা আপনি যে টিকাটি দেননি সেগুলি ইনলাইন করতে মুক্ত। বরং মূলশব্দটির আসল উদ্দেশ্য inlineহ'ল একাধিক সংজ্ঞা ত্রুটিগুলি আটকানো।
আন্ডারস্কোর_ডি

উত্তর:


121

প্রস্তাবনার প্রথম বাক্য:

"inline সুনির্দিষ্টভাবে উল্লেখ করা ভেরিয়েবল পাশাপাশি ফাংশন প্রয়োগ করা যায়।

inlineকোনও ফাংশনে যেমন প্রয়োগ করা হয় তার গ্যারান্টেড এফেক্টটি হ'ল একাধিক অনুবাদ ইউনিটগুলিতে বাহ্যিক সংযোগের সাথে ফাংশনটি অভিন্নভাবে সংজ্ঞায়িত করা allow অনুশীলনের জন্য মানে শিরোনামে ফাংশনটি সংজ্ঞায়িত করা, এটি একাধিক অনুবাদ ইউনিটে অন্তর্ভুক্ত করা যেতে পারে। প্রস্তাবটি এই সম্ভাবনাকে ভেরিয়েবলগুলিতে প্রসারিত করে।

সুতরাং, ব্যবহারিক পদগুলিতে (এখন স্বীকৃত) প্রস্তাবনা আপনাকে একটি শিরোলেখ ফাইলটিতে inlineএকটি বহিরাগত লিঙ্কেজ constনেমস্পেস স্কোপ ভেরিয়েবল বা কোনও staticশ্রেণির ডেটা সদস্যকে সংজ্ঞায়িত করতে কীওয়ার্ডটি ব্যবহার করার অনুমতি দেয় , যাতে সেই শিরোনামটি অন্তর্ভুক্ত করার সময় একাধিক সংজ্ঞা সংঘটিত হয় একাধিক অনুবাদ ইউনিট লিঙ্কারের সাথে ঠিক আছে - এটি কেবল তাদের মধ্যে একটি বেছে নেয় ।

staticক্লাস টেমপ্লেটগুলিতে ভেরিয়েবল সমর্থন করার জন্য সি ++ 14 পর্যন্ত অভ্যন্তরীণ যন্ত্রপাতিটি ছিল, তবে সেই যন্ত্রপাতিটি ব্যবহার করার কোনও সুবিধাজনক উপায় ছিল না। একের মতো কৌশল অবলম্বন করতে হয়েছিল

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`.

সি ++ 17 থেকে এবং আমি বিশ্বাস করি যে কেউ কেবল লিখতে পারে

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

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

… একটি শিরোনাম ফাইল।

প্রস্তাবে শব্দের অন্তর্ভুক্ত রয়েছে

একটি ইনলাইন স্থিতিশীল ডেটা সদস্যকে শ্রেণীর সংজ্ঞায় সংজ্ঞায়িত করা যায় এবং একটি ব্রেস-বা-সমান-আরম্ভকারীকে প্রশমিত করতে পারে। সদস্যটি যদি constexprস্পেসিফায়ারের সাথে ঘোষণা করা হয় , তবে এটি কোনও প্রাথমিককরণ ছাড়াই নাম স্পেসে পুনরায় ঘোষিত হতে পারে (এই ব্যবহারটি অবচিত হয়; দেখুন ডেক্স)। অন্যান্য স্থিতিশীল ডেটা সদস্যদের ঘোষণাগুলি কোনও ব্রেস-বা-সমান-ইন it আইটিয়ালাইজার নির্দিষ্ট করে না

… যা উপরোক্তটিকে আরও সরল করে মঞ্জুরি দেয়

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

… এই উত্তরের একটি মন্তব্যে টিসি যেমন উল্লেখ করেছেন ।

এছাড়াও,  ​constexprনির্দিষ্টকারক inline স্থিতিশীল ডেটা সদস্যদের পাশাপাশি কার্যকারিতা বোঝায়  ।


নোটস:
a কোনও ফাংশনের inlineজন্য অপ্টিমাইজেশন সম্পর্কে একটি হিন্টিং প্রভাবও রয়েছে, যে সংকলকটির এই ফাংশনের কলগুলি ফাংশনের মেশিন কোডের প্রত্যক্ষ প্রতিস্থাপনের সাথে প্রতিস্থাপন করতে পছন্দ করা উচিত। এই ইঙ্গিতটি এড়ানো যায়।


2
এছাড়াও, সীমাবদ্ধতার সীমাবদ্ধতা কেবলমাত্র নামস্থান স্কোপ ভেরিয়েবলগুলিতে প্রযোজ্য। ক্লাস-স্কোপগুলি (পছন্দ করা Kath::hi) কনস্টের হতে হবে না।
টিসি

4
নতুন প্রতিবেদনগুলি নির্দেশ করে যে এই constনিষেধাজ্ঞাকে পুরোপুরি বাদ দেওয়া হয়েছে।
টিসি

2
@ নিক: যেহেতু রিচার্ড স্মিথ (বর্তমান সি ++ কমিটি "প্রকল্প সম্পাদক") এই দুই লেখকের একজন এবং তিনি যেহেতু "ক্ল্যাং সি ++ ফ্রন্ট্যান্ডের কোড মালিক", তাই কলং অনুমান করেছিলেন। এবং গডবোল্টে 3..৯.০ ওভারের সাথে কনস্ট্রাক্ট নির্মাণ করা হয়েছে । এটি সতর্ক করে দিয়েছে যে ইনলাইন ভেরিয়েবলগুলি একটি C ++ 1z এক্সটেনশন। উত্স এবং সংকলক পছন্দ এবং বিকল্পগুলি ভাগ করার কোনও উপায় আমি পাইনি, সুতরাং লিঙ্কটি কেবলমাত্র সাইটের সাধারণভাবে, দুঃখিত।
চিয়ার্স এবং এইচটিএইচ - আলফ

1
শ্রেণি / কাঠামো ঘোষণার ভিতরে কেন ইনলাইন কীওয়ার্ডের প্রয়োজন? কেন সহজভাবে অনুমতি দিচ্ছেন না static std::string const hi = "Zzzzz...";?
sasha.sochka

2
@ এমিলিয়ানসিওকা: না, আপনি স্থির সূচনা অর্ডার ফিয়াস্কোর চেয়ে অনেক বেশি চালিয়ে যাবেন । এটি এড়ানোর জন্য একটি সিঙ্গলটন মূলত একটি ডিভাইস।
চিয়ার্স এবং এইচটিএইচ - আলফ

15

ইনলাইন ভেরিয়েবলগুলি ইনলাইন ফাংশনের সাথে খুব মিল। এটি লিঙ্কারের সংকেত দেয় যে ভ্যারিয়েবলটি একাধিক সংকলন ইউনিটে দেখা গেলেও কেবলমাত্র ভেরিয়েবলের একটি মাত্র উপস্থিতি থাকা উচিত। লিঙ্কারটির যাতে আরও অনুলিপি তৈরি না হয় তা নিশ্চিত হওয়া দরকার।

কেবলমাত্র শিরোনামের লাইব্রেরিতেই ইনলাইন ভেরিয়েবলগুলি গ্লোবালগুলি সংজ্ঞায়িত করতে ব্যবহৃত হতে পারে। সি ++ 17 এর আগে তাদের workaround (ইনলাইন ফাংশন বা টেমপ্লেট হ্যাক) ব্যবহার করতে হয়েছিল।

উদাহরণস্বরূপ, একটি কার্যপ্রণালী হ'ল মেইল এর সিঙ্গলটন একটি ইনলাইন ফাংশন সহ ব্যবহার করা:

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

বেশিরভাগ পারফরম্যান্সের ক্ষেত্রে এই পদ্ধতির সাথে কিছু ত্রুটি রয়েছে। এই ওভারহেডটি টেমপ্লেট সমাধানগুলি এড়ানো যেতে পারে তবে এগুলি ভুল হওয়া সহজ।

ইনলাইন ভেরিয়েবলের সাহায্যে আপনি সরাসরি এটি ঘোষণা করতে পারেন (একাধিক সংজ্ঞা লিঙ্কারের ত্রুটি না পেয়ে):

inline T global;

কেবল শিরোনামের পাঠাগারগুলি ছাড়াও অন্যান্য ক্ষেত্রে ইনলাইন ভেরিয়েবলগুলি সহায়তা করতে পারে। সিপিপোন-তে তাঁর আলাপে নীড় ফ্রেডম্যান এই বিষয়টিকে কভার করেন: গ্লোবালগুলি (এবং লিঙ্কার) সম্পর্কে সি ++ বিকাশকারীদের কী জানা উচিত । ইনলাইন ভেরিয়েবল এবং সমাধান নীচে উপস্থিত সম্পর্কে অংশ 18m9s আরম্ভ করা হয়

সংক্ষিপ্ত ইউনিটগুলির মধ্যে ভাগ করা গ্লোবাল ভেরিয়েবলগুলি যদি আপনাকে শিরোনাম ফাইলে ইনলাইন ভেরিয়েবল হিসাবে ঘোষণা করা সোজা হয় এবং প্রি-সি ++ 17 ওয়ার্কআউন্ডের সমস্যাগুলি এড়ানো যায় তবে আপনার দীর্ঘ সংক্ষিপ্ত বিবরণটি সংক্ষেপে if

(উদাহরণস্বরূপ, আপনি যদি অলস সূচনা করতে চান তবে মায়ারের সিঙ্গলটনের জন্য এখনও ব্যবহারের কেস রয়েছে))


11

ন্যূনতম চলমান উদাহরণ

এই দুর্দান্ত সি ++ 17 বৈশিষ্ট্যটি আমাদের এতে অনুমতি দেয়:

  • প্রতিটি ধ্রুবক জন্য সুবিধামত কেবল একটি একক মেমরি ঠিকানা ব্যবহার করুন
  • এটি একটি হিসাবে সংরক্ষণ করুন constexpr: কীভাবে বহিরাগতকে ঘোষণা করবেন?
  • এটি একটি শিরোলেখ থেকে একক লাইনে করুন

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

গিটহাব উজানের দিকে

আরও দেখুন: ইনলাইন ভেরিয়েবলগুলি কীভাবে কাজ করে?

ইনলাইন ভেরিয়েবলগুলিতে সি ++ স্ট্যান্ডার্ড

সি ++ স্ট্যান্ডার্ড গ্যারান্টি দেয় যে ঠিকানাগুলি একই হবে। সি ++ 17 এন 4659 স্ট্যান্ডার্ড খসড়া 10.1.6 "ইনলাইন স্পেসিফায়ার":

External বাহ্যিক সংযোগের সাথে একটি ইনলাইন ফাংশন বা ভেরিয়েবলের সমস্ত অনুবাদ ইউনিটে একই ঠিকানা থাকবে।

cppreferences https://en.cppreferences.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:

"u" প্রতীকটি একটি অনন্য বৈশ্বিক প্রতীক। এটি ELF প্রতীক বাইন্ডিংয়ের মানক সেটটিতে একটি GNU এক্সটেনশন। এই জাতীয় প্রতীকের জন্য ডায়নামিক লিঙ্কার নিশ্চিত করবে যে পুরো প্রক্রিয়াতে এই নাম এবং ব্যবহারের টাইপ সহ কেবল একটি প্রতীক রয়েছে।

সুতরাং আমরা দেখতে পাচ্ছি যে এর জন্য একটি ডেডিকেটেড ইএলএফ এক্সটেনশন রয়েছে।

প্রাক-সি ++ 17: extern const

সি ++ 17 এর আগে এবং সি-তে আমরা একটির সাথে খুব অনুরূপ প্রভাব অর্জন করতে পারি extern constযা একটি একক মেমরি অবস্থান ব্যবহারের দিকে নিয়ে যাবে।

ডাউনসাইডগুলি হ'ল 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বোঝাinline এবং inline পারবেন (বাহিনী) সংজ্ঞা প্রত্যেক অনুবাদ ইউনিট প্রদর্শিত :

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.cppreferences.com/w/cpp/language/static "কনস্ট্যান্ট স্ট্যাটিক সদস্য" এবং কনটেক্সট্রিক স্ট্যাটিক ডেটা সংজ্ঞায়িত করা সদস্যদের

সি

সিতে পরিস্থিতি সি ++ প্রাক সি ++ 17 এর মতোই, আমি এখানে একটি উদাহরণ আপলোড করেছি: "স্ট্যাটিক" সি এর অর্থ কী?

মাত্র তফাত হল যে সি ++ হয় constবোঝা staticglobals জন্য, কিন্তু এটা সি না: বনাম `const`` স্ট্যাটিক const` এর সি ++ শব্দার্থবিদ্যা

এটি সম্পূর্ণরূপে ইনলাইন করার কোনও উপায়?

টোডো: কোনও স্মৃতি ব্যবহার না করে ভেরিয়েবলকে সম্পূর্ণরূপে ইনলাইন করার কোনও উপায় আছে কি?

প্রিপ্রোসেসর কী করে তা অনেকটা পছন্দ করে।

এটির কোনওরকম প্রয়োজন হবে:

  • পরিবর্তনশীলের ঠিকানা নেওয়া হয়েছে কিনা তা নিষিদ্ধ বা সনাক্তকরণ
  • ELF অবজেক্ট ফাইলগুলিতে সেই তথ্য যুক্ত করুন, এবং LTO এটির সর্বোত্তম করুন

সম্পর্কিত:

উবুন্টু 18.10, জিসিসি 8.2.0 এ পরীক্ষিত।


2
inlineশব্দটি সত্ত্বেও ইনলাইনিংয়ের সাথে ফাংশন বা ভেরিয়েবলের জন্য প্রায় কিছুই করার নেই। inlineসংকলককে কোনও কিছুর ইনলাইন করতে বলে না। এটি লিঙ্ককারীকে নিশ্চিত করে যে এটির একটিমাত্র সংজ্ঞা আছে, যা traditionতিহ্যগতভাবে প্রোগ্রামারের কাজ হয়ে গেছে। সুতরাং "এটির পুরোপুরি ইনলাইন করার কোনও উপায়?" অন্তত একটি সম্পূর্ণ সম্পর্কযুক্ত প্রশ্ন।
না-ব্যবহারকারীর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.