এক ফাংশন কল সি ++ ব্যবহার করে একাধিক ধ্রুবক শ্রেণীর সদস্যদের সূচনা করুন


50

আমার যদি দুটি পৃথক ধ্রুবক সদস্যের ভেরিয়েবল থাকে, যা উভয়টির একই ফাংশন কলের ভিত্তিতে আরম্ভ করা দরকার, ফাংশনটি দুটিবার কল না করে এটি করার কোনও উপায় আছে কি?

উদাহরণস্বরূপ, একটি ভগ্নাংশ শ্রেণি যেখানে অংকের এবং ডিনোমিনিটর স্থির থাকে।

int gcd(int a, int b); // Greatest Common Divisor
class Fraction {
public:
    // Lets say we want to initialize to a reduced fraction
    Fraction(int a, int b) : numerator(a/gcd(a,b)), denominator(b/gcd(a,b))
    {

    }
private:
    const int numerator, denominator;
};

জিসিডি ফাংশনটি দু'বার ডাকা হওয়ার কারণে এটি নষ্ট সময়ে ফলাফল দেয়। আপনি কোনও নতুন শ্রেণীর সদস্যকে সংজ্ঞায়িত করতে পারেন gcd_a_b, এবং প্রথমে প্রারম্ভিক তালিকায় সেই সাথে জিসিডি আউটপুট বরাদ্দ করতে পারেন, তবে তারপরে এটি নষ্ট স্মৃতিতে বাড়ে।

সাধারণভাবে, নষ্ট ফাংশন কল বা মেমরি ছাড়াই এটি করার কোনও উপায় আছে? আপনি সম্ভবত একটি প্রাথমিকের তালিকায় অস্থায়ী পরিবর্তনগুলি তৈরি করতে পারেন? ধন্যবাদ.


5
আপনার কাছে কি প্রমাণ আছে যে "জিসিডি ফাংশনটি দু'বার বলা হয়"? এটি দু'বার উল্লেখ করা হয়েছে, তবে এটি সংকলক নির্গত কোড হিসাবে একই জিনিস নয় যা এটিকে দু'বার কল করে। একটি সংকলক এটি নির্ধারণ করতে পারে যে এটি একটি খাঁটি ফাংশন এবং দ্বিতীয়টির উল্লেখে এর মান পুনরায় ব্যবহার করতে পারে।
এরিক টাওয়ার

6
@ এরিক টাওয়ারস: হ্যাঁ, সংকলকরা মাঝে মাঝে কিছু ক্ষেত্রে অনুশীলনে সমস্যাটি ঘিরে কাজ করতে পারে। তবে কেবলমাত্র যদি তারা সংজ্ঞাটি দেখতে পায় (বা কোনও জিনিসে কিছু টিকা), অন্যথায় এটি খাঁটি প্রমাণ করার কোনও উপায় নেই। আপনার লিঙ্ক-টাইম অপ্টিমাইজেশন সক্ষম করার সাথে সংকলন করা উচিত , তবে সবাই তা করে না। এবং ফাংশনটি একটি লাইব্রেরিতে থাকতে পারে। বা এমন কোনও ফাংশনের ক্ষেত্রে বিবেচনা করুন যার পার্শ্ব-প্রতিক্রিয়া রয়েছে এবং একে একে একবার কল করা যথার্থতা?
পিটার কর্ডেস

@ এরিক টাওয়ার আকর্ষণীয় পয়েন্ট আমি জিসিডি ফাংশনের ভিতরে একটি মুদ্রণ বিবৃতি রেখে এটি যাচাই করার চেষ্টা করেছি, তবে এখন আমি বুঝতে পেরেছি যে এটি এটিকে খাঁটি ফাংশন হতে আটকাবে।
QQ0

@ কিউকিউ 0: আপনি উত্পাদিত asm সংকলকটি দেখে পরীক্ষা করতে পারেন, যেমন জিডিসি বা ক্ল্যাংয়ের সাথে গডবোল্ট সংকলক এক্সপ্লোরার ব্যবহার করে-O3 । তবে সম্ভবত কোনও সাধারণ পরীক্ষার বাস্তবায়নের জন্য এটি ফাংশন কলটি ইনলাইন করবে line আপনি যদি __attribute__((const))কোনও দৃশ্যমান সংজ্ঞা না দিয়ে প্রোটোটাইপটিতে শুদ্ধ ব্যবহার করেন বা শুদ্ধ হন, এটি একই আর্গ দিয়ে দুটি কলের মধ্যে জিসিসি বা ক্ল্যাংকে সাধারণ-সুপ্রেসপ্রেসেশন নির্মূলকরণ (সিএসই) করতে দেওয়া উচিত। মনে রাখবেন যে ড্রুর উত্তরটি খাঁটি অ-কার্যকারী কাজের জন্যও কাজ করে তাই এটি আরও ভাল এবং ফানকটি ইনলাইন না করে এমন কোনও সময় আপনার এটি ব্যবহার করা উচিত।
পিটার কর্ডস

সাধারণত, অ স্থিতিশীল কনস্টের সদস্য ভেরিয়েবলগুলি সর্বোত্তম এড়ানো হয়। কনস্টের সমস্ত কিছু প্রায়শই প্রয়োগ হয় না এমন কয়েকটি ক্ষেত্রে একটি। উদাহরণস্বরূপ আপনি শ্রেণি অবজেক্টগুলি বরাদ্দ করতে পারবেন না। আপনি ভ্যাক্টরে এমপ্লেস_ব্যাক করতে পারেন তবে কেবলমাত্র যতক্ষণ ক্ষমতার সীমা একটি আকার পরিবর্তন করতে না পারে।
ডগ

উত্তর:


67

সাধারণভাবে, নষ্ট ফাংশন কল বা মেমরি ছাড়াই এটি করার কোনও উপায় আছে?

হ্যাঁ. এটি সি ++ 11-এ প্রবর্তিত একটি প্রতিনিধি কনস্ট্রাক্টরের সাথে করা যেতে পারে ।

কোনও সদস্য ভেরিয়েবল সূচনা করার আগে নির্মাণের জন্য প্রয়োজনীয় অস্থায়ী মান অর্জনের জন্য একটি প্রতিনিধি কনস্ট্রাক্টর একটি খুব কার্যকর উপায় ।

int gcd(int a, int b); // Greatest Common Divisor
class Fraction {
public:
    // Call gcd ONCE, and forward the result to another constructor.
    Fraction(int a, int b) : Fraction(a,b,gcd(a,b))
    {
    }
private:
    // This constructor is private, as it is an
    // implementation detail and not part of the public interface.
    Fraction(int a, int b, int g_c_d) : numerator(a/g_c_d), denominator(b/g_c_d)
    {
    }
    const int numerator, denominator;
};

আগ্রহের বাইরে, অন্য নির্মাণকারীকে কল করা থেকে ওভারহেডটি কী তাৎপর্যপূর্ণ হবে?
QQ0

1
@ কিউকিউ 0 আপনি এখানে পর্যবেক্ষণ করতে পারেন যে পরিমিত অপ্টিমাইজেশান সক্ষম করার সাথে কোনও ওভারহেড নেই।
ড্রয় ডোরম্যান

2
@ কিউকি0: সি ++ আধুনিক অপ্টিমাইজ করা সংকলকগুলির চারপাশে ডিজাইন করা হয়েছে। তারা এই প্রতিনিধি দলকে তুচ্ছভাবে ইনলাইন করতে পারে, বিশেষত যদি আপনি শ্রেণীর সংজ্ঞা (দ্য .h) এর মধ্যে দৃশ্যমান করেন , এমনকি প্রকৃত নির্মাণকারীর সংজ্ঞা ইনলাইনিংয়ের জন্য দৃশ্যমান নাও হয়। অর্থাত্ gcd()কলটি প্রতিটি কন্সট্রাক্টর কলসাইটে ইনলাইন করে, এবং কেবলমাত্র call3-অপারেন্ড বেসরকারী কনস্ট্রাক্টরের কাছে ছেড়ে যায়।
পিটার কর্ডেস

10

সদস্য ওয়ার্সগুলি ক্লাস ডিক্লেরেশনে ঘোষিত আদেশ অনুসারে শুরু করা হয়, সুতরাং আপনি নিম্নলিখিতটি করতে পারেন (গাণিতিকভাবে)

#include <iostream>
int gcd(int a, int b){return 2;}; // Greatest Common Divisor of (4, 6) just to test
class Fraction {
public:
    // Lets say we want to initialize to a reduced fraction
    Fraction(int a, int b) : numerator{a/gcd(a,b)}, denominator(b/(a/numerator))
    {

    }
//private:
    const int numerator, denominator;//make sure that they are in this order
};
//Test
int main(){
    Fraction f{4,6};
    std::cout << f.numerator << " / " << f.denominator;
}

অন্য কন্সট্রাক্টরদের কল করার বা এমনকি তাদের তৈরি করার প্রয়োজন নেই।


6
ঠিক আছে যা জিসিডির জন্য বিশেষভাবে কাজ করে, তবে অন্যান্য অনেকগুলি ব্যবহারের ক্ষেত্রে সম্ভবত দ্বিতীয় আর্টটি প্রথম এবং প্রথমটি থেকে পাওয়া যায় না। এবং লিখিত হিসাবে এটির একটি অতিরিক্ত বিভাগ রয়েছে যা বনামের তুলনায় আরেকটি ডাউনসাইড ideal আদর্শ যে সংকলকটি সম্ভবত এটি অপ্টিমাইজ করতে পারে না। জিসিডির জন্য কেবলমাত্র একটি বিভাগের দাম পড়তে পারে তাই এটি দুবার জিসিডি কল করার মতো খারাপ হতে পারে। (ধরে নিই যে বিভাগটি অন্যান্য ক্রিয়াকলাপগুলির ব্যয়কে প্রাধান্য দেয়, যেমন এটি প্রায়শই আধুনিক সিপিইউগুলিতে হয়))
পিটার কর্ডেস

@ পিটারকর্ডস তবে অন্য সমাধানটিতে অতিরিক্ত ফাংশন কল রয়েছে এবং আরও নির্দেশ মেমরি বরাদ্দ করে।
asmmo

1
আপনি কি ড্রুর প্রতিনিধি নির্মাণকারীর কথা বলছেন? এটি স্পষ্টভাবে Fraction(a,b,gcd(a,b))প্রতিনিধিকে কলারের সাথে ইনলাইন করতে পারে , যার ফলে মোট ব্যয় কম হয়। এই অতিরিক্ত বিভাগটিকে পূর্বাবস্থায়িত করার চেয়ে সংযোজকটির পক্ষে ইনলাইনিং করা সহজ। আমি Godbolt.org এ চেষ্টা করিনি তবে আপনি যদি আগ্রহী হন তবে আপনি তা করতে পারতেন। -O3সাধারণ বিল্ডের মতো জিসিসি বা ক্ল্যাং ব্যবহার করুন। (সি ++ আধুনিক অপ্টিমাইজিং সংকলকের অনুমানের আশেপাশে তৈরি করা হয়েছে, সুতরাং এর মতো বৈশিষ্ট্যগুলি রয়েছে constexpr)
পিটার কর্ডেস

-3

@ ড্রু ডোরম্যান আমার মনের মতোই একটি সমাধান দিয়েছেন। যেহেতু ওপি কখনই কর্টরটিকে সংশোধন করতে না পারার কথা উল্লেখ করে না, তাই এটি দিয়ে এটি কল করা যেতে পারে Fraction f {a, b, gcd(a, b)}:

Fraction(int a, int b, int tmp): numerator {a/tmp}, denominator {b/tmp}
{
}

কেবলমাত্র এই পথে কোনও ফাংশন, কনস্ট্রাক্টর বা অন্যথায় দ্বিতীয় কল নেই, সুতরাং এটি কোনও সময় নষ্ট করে না। এবং এটি কোনও নষ্ট স্মৃতি নয় যেহেতু একটি অস্থায়ীভাবে তৈরি করতে হবে, সুতরাং আপনি এটিরও ভাল ব্যবহার করতে পারেন। এটি একটি অতিরিক্ত বিভাগও এড়িয়ে যায়।


3
আপনার সম্পাদনা এটি এমনকি প্রশ্নের উত্তর দেয় না। এখন আপনি কলারকে তৃতীয় তর্কটি পাস করার জন্য প্রয়োজনীয়তা দিচ্ছেন? কনস্ট্রাক্টর বডির ভিতরে অ্যাসাইনমেন্ট ব্যবহার করে আপনার আসল সংস্করণটি কাজ করে না const, তবে কমপক্ষে অন্যান্য ধরণের জন্য কাজ করে। এবং আপনি "এছাড়াও" কোন অতিরিক্ত বিভাগ এড়িয়ে চলেছেন? আপনার মানে বনাম অ্যাস্মো এর উত্তর?
পিটার কর্ডেস

1
ঠিক আছে, এখন আমার ডাউনভোটটি সরানো হয়েছে যে আপনি আপনার বক্তব্যটি ব্যাখ্যা করেছেন। তবে এটি দেখতে বেশ স্পষ্টতই ভয়াবহ বলে মনে হচ্ছে এবং আপনাকে প্রতিটি কলারের মধ্যে কয়েকটি নির্মাণকারীর কাজ ম্যানুয়ালি ইনলাইন করা প্রয়োজন। এটি ডিআরওয়াইর বিপরীত (নিজেকে পুনরাবৃত্তি করবেন না) এবং শ্রেণীর দায়িত্ব / ইন্টার্নালদের encapsulation। বেশিরভাগ লোক এটিকে গ্রহণযোগ্য সমাধান হিসাবে বিবেচনা করবেন না। পরিষ্কারভাবে এটি করার জন্য একটি সি ++ 11 উপায় রয়েছে তা প্রদত্ত, কোনও পুরানো সি ++ সংস্করণে আটকে না থাকলে কারও কখনও এটি করা উচিত নয় এবং ক্লাসটির এই নির্মাতার কাছে খুব কম কল রয়েছে।
পিটার কর্ডেস

2
টুইট আপনার পথের সাহায্যে, আপনি যদি কখনও পরিবর্তন করেন যে এই শ্রেণিটি অভ্যন্তরীণভাবে কীভাবে কাজ করে তবে আপনাকে কনস্ট্রাক্টরের সমস্ত কল সন্ধান করতে হবে এবং 3rd য় আর্গ পরিবর্তন করতে হবে। যে অতিরিক্ত ,gcd(foo, bar)অতিরিক্ত কোডটি এবং সেইজন্য যে callsite বাইরে উপাদান দিতে হবে পারে সোর্সে । এটি একটি রক্ষণাবেক্ষণ / পঠনযোগ্যতা ইস্যু, কর্মক্ষমতা নয়। সংকলকটি সম্ভবত সংকলনের সময় এটিকে ইনলাইন করবে, যা আপনি সম্পাদনার জন্য চান।
পিটার কর্ডেস

1
@ পিটারকর্ডস আপনি ঠিক বলেছেন, এখন আমি দেখছি সমাধানের দিকে আমার মন স্থির ছিল, এবং আমি সমস্ত কিছু উপেক্ষা করেছি। যেভাবেই হোক, উত্তরটি কেবল লজ্জার জন্যই থাকে। যখনই আমার এ সম্পর্কে সন্দেহ হবে, আমি কোথায় সন্ধান করব তা জানব।
একটি সম্পর্কিত নাগরিক

1
Fraction f( x+y, a+b ); এটিকে আপনার উপায়ে লেখার ক্ষেত্রে বিবেচনা করুন , আপনাকে লিখতে BadFraction f( x+y, a+b, gcd(x+y, a+b) );বা tmp vars ব্যবহার করতে হবে। বা আরও খারাপ, আপনি যদি লিখতে চান Fraction f( foo(x), bar(y) );- তবে আপনার কল সাইটের দরকার হবে যে রিটার্ন মানগুলি ধরে রাখার জন্য কিছু টিএমপি ভার ঘোষণা করতে হবে, বা সেই ফাংশনগুলি আবার কল করুন এবং সংকলক সিএসই তাদের দূরে রাখবেন, যা আমরা এড়াচ্ছি। আপনি কি একজন কলারের সাথে আরোগ্যগুলি মিশ্রিত করার ক্ষেত্রে এটি ডিবাগ করতে চান gcdযাতে এটি নির্মাণকারীর কাছে প্রথম 2 টি আর্গের জিসিডি আসলে না? কোন? তারপরে সেই বাগটিকে সম্ভব করবেন না।
পিটার কর্ডেস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.