সি ++ এ অস্থায়ী জীবনের গ্যারান্টিযুক্ত?


103

সি ++ একটি অস্থায়ী পরিবর্তনশীল যা প্যারামিটার হিসাবে ব্যবহার না করে একটি অস্থায়ী পরিবর্তনশীলের আজীবন গ্যারান্টি সরবরাহ করে? এখানে একটি উদাহরণ বর্গ:

class StringBuffer
{
public:
    StringBuffer(std::string & str) : m_str(str)
    {
        m_buffer.push_back(0);
    }
    ~StringBuffer()
    {
        m_str = &m_buffer[0];
    }
    char * Size(int maxlength)
    {
        m_buffer.resize(maxlength + 1, 0);
        return &m_buffer[0];
    }
private:
    std::string & m_str;
    std::vector<char> m_buffer;
};

আপনি এখানে এটি কীভাবে ব্যবহার করবেন তা এখানে:

// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);

std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);

অস্থায়ী স্ট্রিংবাফার অবজেক্টের জন্য ডেস্ট্রাক্টরকে কখন ডাকা হবে? তাই কি:

  • গেটস্ট্রিংয়ের কল করার আগে?
  • গেটস্ট্রিং রিটার্নের পরে?
  • সংকলক নির্ভর?

আমি জানি যে সি ++ গ্যারান্টি দেয় যে কোনও স্থানীয় অস্থায়ী পরিবর্তনশীল যতক্ষণ তার রেফারেন্স রয়েছে ততক্ষণ বৈধ হবে - যখন কোনও সদস্যের ভেরিয়েবলের রেফারেন্স থাকে তখন পিতামাতাদের জন্য এটি প্রয়োগ হয়?

ধন্যবাদ।


কেন উত্তরাধিকারী এবং ওভারলোড বা একটি বিশ্বব্যাপী ফাংশন করবেন না? আমি ক্লিনার হতে হবে এবং কোনও সদস্যকে কল করার জন্য আপনাকে কোনও গোষ্ঠী তৈরি করতে হবে না।
জ্যাসেক আউরআউনিউইচিজ

1
আপনি এই ব্যবহার করতে যাচ্ছি, তাহলে আপনি কল করা উচিত m_str.reserve(maxlength)মধ্যে char * Size(int maxlength), অন্যথায় বিনাশকারী নিক্ষেপ পারে।
মানকারসে

উত্তর:


109

এই ধরণের টেম্পোরারিগুলির জন্য ডেস্ট্রাক্টরকে পূর্ণ-প্রকাশের শেষে বলা হয়। এটি সর্বাধিক বাহ্যিক অভিব্যক্তি যা অন্য কোনও অভিব্যক্তির অংশ নয়। ফাংশনটি ফিরে আসার পরে এবং মূল্য নির্ধারণের পরে এটি আপনার ক্ষেত্রে। সুতরাং, এটি দুর্দান্ত কাজ করবে।

প্রকৃতপক্ষে এটিই কী অভিব্যক্তি টেম্পলেটগুলিকে কাজ করে: এগুলি যেমন প্রকাশের ক্ষেত্রে সেই ধরণের টেম্পোরারিগুলির রেফারেন্স ধরে রাখতে পারে

e = a + b * c / d

কারণ প্রতিটি অস্থায়ী প্রকাশ অবধি অবধি স্থায়ী হয়

x = y

সম্পূর্ণ মূল্যায়ন করা হয়। এটি 12.2 Temporary objectsস্ট্যান্ডার্ডে বেশ সংক্ষেপে বর্ণনা করা হয়েছে।


3
আমি কখনও স্ট্যান্ডার্ড একটি অনুলিপি পেতে কাছাকাছি না। আমার এটিকে অগ্রাধিকার দেওয়া উচিত।
মার্ক রান্সম

2
@ জোহানেসচাব: এই ক্ষেত্রে একটি "সম্পূর্ণ-এক্সপ্রেশন" কী:? printf("%s", strdup(std::string("$$$").c_str()) );মানে আমি যদি strdup(std::string("$$$").c_str())সম্পূর্ণ প্রকাশ হিসাবে বিবেচনা করা হয় তবে যে পয়েন্টারটি strdupদেখেছে তা বৈধ । যদি std::string("$$$").c_str()একটি পূর্ণ এক্সপ্রেশন হয়, তবে যে পয়েন্টারটি strdupদেখছে তা অবৈধ ! আপনি দয়া করে এই উদাহরণের উপর ভিত্তি করে কিছুটা আরও ব্যাখ্যা করতে পারেন?
গ্রিম ফান্ডাঙ্গো

2
@ গ্রিমফান্ডাঙ্গো এআইইউআই আপনার সম্পূর্ণরূপে printfসম্পূর্ণ অভিব্যক্তি। সুতরাং এটি strdupএকটি অপ্রয়োজনীয় মেমরি ফাঁস - আপনি কেবল এটি c_str()সরাসরি মুদ্রণ করতে দিতে পারেন ।
জোশ স্টোন

1
"এই ধরণের টেম্পোরারিগুলি" - এটি কোন ধরণের? আমার অস্থায়ী অস্থায়ী "সেই ধরণের" কিনা তা আমি কীভাবে বলতে পারি?
আরএম

@ আরএম মোটামুটি প্রশ্নের অর্থ যেমনটি হয়েছে "আপনি যা একটি ফাংশন আর্গুমেন্টের মধ্যে তৈরি করেন" তার অর্থ।
জোহানেস স্কাউব -

18

litb এর উত্তর সঠিক। অস্থায়ী বস্তুর জীবদ্দশায় (একটি মূল্যবোধ হিসাবেও পরিচিত) প্রকাশের সাথে আবদ্ধ হয় এবং অস্থায়ী অবজেক্টের জন্য ডেস্ট্রাক্টরকে সম্পূর্ণ এক্সপ্রেশনের শেষে বলা হয় এবং যখন স্ট্রিংবাফারে ডেস্ট্রাক্টর ডাকা হয় তখন এম_বফারের ডেস্ট্রাক্টরও হবে বলা হয়, তবে মি_স্ট্রিতে ডেস্ট্রাক্টর নয় কারণ এটি একটি উল্লেখ।

মনে রাখবেন যে সি ++ 0 এক্স জিনিসগুলিকে কিছুটা পরিবর্তন করে কারণ এটি মূল্যের রেফারেন্সগুলি যুক্ত করে এবং শব্দার্থবিজ্ঞানকে সরায়। মূলত একটি মূল্যের রেফারেন্স প্যারামিটার ব্যবহার করে (&& এর সাথে চিহ্নিত) আমি ক্রিয়াকলাপটি (এটি অনুলিপি করার পরিবর্তে) 'স্থানান্তর' করতে পারি এবং মূল্যের আজীবন অবজেক্টের পরিবর্তে অবজেক্টের সাথে আবদ্ধ হতে পারে যা এতে স্থানান্তরিত হয়। এমএসভিসি টিমের একটি সত্যিকারের ভাল ব্লগ পোস্ট রয়েছে যেটিতে এটি দুর্দান্তভাবে চলছে এবং আমি লোকেরা এটি পড়তে উত্সাহিত করি।

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

class MyType{
   const std::string m_name;
public:
   MyType(const std::string&& name):m_name(name){};
}

এটি দুর্দান্ত কারণ কারণ আমি যখন অস্থায়ী বস্তু সহ এই শ্রেণীর কোনও উদাহরণ ঘোষণা করি:

void foo(){
    MyType instance("hello");
}

যা ঘটে তা হ'ল আমরা অস্থায়ী বস্তুটি অনুলিপি করা এবং ধ্বংস করা এড়ানোর জন্য এবং "হ্যালো" সরাসরি নিজের শ্রেণীর উদাহরণের সদস্য ভেরিয়েবলের ভিতরে স্থাপন করা হয়। যদি কোনও স্ট্রিংয়ের চেয়ে ওজনটি ভারী হয় তবে অতিরিক্ত অনুলিপি এবং ডেস্ট্রাক্টর কলটি তাৎপর্যপূর্ণ হতে পারে।


1
সরানোর কাজটি করার জন্য আমার মনে হয় আপনার কনস্টটি ফেলে ফেলতে হবে এবং std :: MyType (std :: স্ট্রিং এবং& নাম) এর মতো চলুন: m_name (std :: ચાલ (নাম)) {}
gast128


3

স্ট্রিংবফার গেটস্ট্রিংয়ের সুযোগে। এটি getString এর স্কোপ (যেমন ফিরে আসে) শেষে ধ্বংস হওয়া উচিত। এছাড়াও, আমি বিশ্বাস করি না যে সি ++ গ্যারান্টি দেয় যে যতক্ষণ রেফারেন্স থাকবে ততক্ষণ চলক বিদ্যমান থাকবে।

নিম্নলিখিতগুলি সংকলন করা উচিত:

Object* obj = new Object;
Object& ref = &(*obj);
delete obj;

আমি মনে করি আমি গ্যারান্টিটিকে ছাড়িয়েছি - এটি কেবল স্থানীয় অস্থায়ীদের জন্য। কিন্তু এটি বিদ্যমান।
মার্ক রান্সম

আমি প্রশ্নটি সম্পাদনা করেছি। এখনও পর্যন্ত সরবরাহ করা উত্তরের উপর ভিত্তি করে, এটি অবশ্য একটি মূল বিষয় বলে মনে হচ্ছে।
মার্ক রান্সম

আমি এখনও আপনার সম্পাদনাটিকে সঠিক বলে মনে করি না: অবজেক্ট & আপজেক্ট = GetObj (); অবজেক্ট এবং গেটবজ () {রিটার্ন এবং অবজেক্ট (); bad // খারাপ - ঝুঁকির রেফারেন্স ছেড়ে দেবে।
বিগস্যান্ডউইচ

1
আমি স্পষ্টতই নিজেকে ব্যাখ্যা করার একটি খারাপ কাজ করছি, এবং আমি সম্ভবত 100% বুঝতে পারি না। এ informit.com/guides/content.aspx?g=cplusplus&seqNum=198 - এটা ব্যাখ্যা করে এবং সেইসাথে আমার মূল প্রশ্নের উত্তর।
মার্ক রান্সম

1
ধন্যবাদ, লিঙ্কটির জন্য, এটি এখন উপলব্ধি হয়ে যায়।
বিগস্যান্ডউইচ

3

আমি প্রায় একই ক্লাসে লিখেছিলাম:

template <class C>
class _StringBuffer
{
    typename std::basic_string<C> &m_str;
    typename std::vector<C> m_buffer;

public:
    _StringBuffer(std::basic_string<C> &str, size_t nSize)
        : m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }

    ~_StringBuffer()
        { commit(); }

    C *get()
        { return &(m_buffer[0]); }

    operator C *()
        { return get(); }

    void commit()
    {
        if (m_buffer.size() != 0)
        {
            size_t l = std::char_traits<C>::length(get());
            m_str.assign(get(), l);    
            m_buffer.resize(0);
        }
    }

    void abort()
        { m_buffer.resize(0); }
};

template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
    { return _StringBuffer<C>(str, nSize); }

স্ট্যান্ডার্ডের আগে প্রতিটি সংকলক এটি আলাদাভাবে করত। আমি বিশ্বাস করি যে সি ++ এর জন্য পুরানো টীকাগুলি রেফারেন্স ম্যানুয়াল নির্দিষ্ট করে দিয়েছে যে অস্থায়ী ক্ষেত্রগুলি শেষে পরিস্কার হওয়া উচিত, তাই কিছু সংকলক এটি করেছিলেন। 2003 এর শেষের দিকে, আমি দেখতে পেয়েছি যে সান এর ফোর্ট সি ++ কম্পাইলারে ডিফল্টরূপে এখনও আচরণটি বিদ্যমান ছিল, তাই স্ট্রিংবাফার কাজ করেনি। তবে যদি কোনও বর্তমান সংকলক এখনও সেই ভাঙা হত তবে আমি অবাক হয়ে যাব।


ভুতুড়ে তারা কেমন মিল! সতর্কতার জন্য ধন্যবাদ - প্রথম স্থানটি আমি চেষ্টা করব এটি ভিসি ++ 6, যা এর মান মেনে চলার জন্য পরিচিত নয়। আমি মনোযোগ দিয়ে দেখছি।
মার্ক রান্সম 21

আমি ক্লাসটি মূলত ভিসি ++ 6 এ লিখে থাকতাম যাতে সমস্যা না হয়।
ড্যানিয়েল আরউইকার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.