কনস্ট স্ট্যান্ড :: স্ট্রিং গ্রহণ এবং 0 গ্রহণ করা থেকে ফাংশন আটকাবেন


97

এক হাজার শব্দ মূল্যবান:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        std::cout<<s<<"\n";
        return *this;
    }
};

int main() {
    SayWhat ohNo;
    // ohNo[1]; // Does not compile. Logic prevails.
    ohNo[0]; // you didn't! this compiles.
    return 0;
}

একটি স্ট্রিং গ্রহণ করে বন্ধনী অপারেটরের কাছে 0 নম্বরটি পাস করার সময় সংকলকটি অভিযোগ করছে না। পরিবর্তে, এই পদ্ধতিতে প্রবেশের আগে এই সংকলন এবং ব্যর্থ হয়:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

রেফারেন্সের জন্য:

> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)

আমার ধারণা

সংকলক সুস্পষ্টভাবে std::string(0)পদ্ধতিতে প্রবেশের জন্য কনস্ট্রাক্টর ব্যবহার করছে , যা কোনও কারণ ছাড়াই একই সমস্যা (উপরের ত্রুটির গুগল) দেয়।

প্রশ্ন

ক্লাস সাইডে এটি ঠিক করার কোনও উপায় আছে, তাই API ব্যবহারকারী এটি অনুভব করে না এবং সংকলনের সময় ত্রুটিটি সনাক্ত করা যায়?

এটি একটি ওভারলোড যুক্ত করা হচ্ছে

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

একটি ভাল সমাধান নয়।


2
সংকলিত কোড, "0xC0000005: 0xC0000005: অ্যাক্সেস লঙ্ঘন পড়ার অবস্থান 0xC00000000 এ ভিজ্যুয়াল স্টুডিওতে ব্যতিক্রম ছোঁড়া"
ট্রুথসাইকার

5
এর একটি ব্যক্তিগত ওভারলোড ঘোষণা করুন operator[]()যে একটি intযুক্তি গ্রহণ করে, এবং এটি সংজ্ঞায়িত করবেন না।
পিটার

2
@ পিটার যদিও নোট করে দেখুন এটি একটি লিঙ্কারের ত্রুটি, যা আমার যা ছিল তার থেকে এখনও ভাল।
কাবানুস

5
@ কাবাবানস উপরের দৃশ্যে এটি একটি সংকলক ত্রুটি হবে কারণ অপারেটরটি ব্যক্তিগত! লিঙ্কারের ত্রুটি কেবল শ্রেণীর মধ্যে বলা হলে ...
অ্যাকোনকাগুয়া

5
@Peter যে পরিস্থিতিতে যেখানে সি ++ 11 পাওয়া যায়, বিশেষ করে আকর্ষণীয় - এবং এই না আজও অস্তিত্ব (আসলে আমি একটি প্রকল্প নিয়ে ভোগ আছি, এবং আমি প্রায় কাছাকাছি নতুন বৈশিষ্ট্যগুলির কয়েকটির অনুপস্থিত করছি ... )।
অ্যাকোনকাগুয়া

উত্তর:


161

কারণটি std::string(0)বৈধ, 0একটি নাল পয়েন্টার ধ্রুবক হওয়ার কারণে । সুতরাং 0 পয়েন্টার গ্রহণ করে স্ট্রিং কনস্ট্রাক্টরের সাথে মেলে। তারপরে কোডটি পূর্ব শর্তের পূর্বে চলে যে কোনও একটি নাল পয়েন্টারটি পাস না করে std::string

কেবল আক্ষরিক 0একটি নাল পয়েন্টার ধ্রুবক হিসাবে ব্যাখ্যা করা হবে, যদি এটি কোনও রান টাইম মান হয় intতবে আপনার এই সমস্যা হবে না (কারণ তারপরে ওভারলোড রেজোলিউশন intপরিবর্তনের জন্য কোনও রূপান্তর খুঁজবে)। আক্ষরিক 1সমস্যাও নয়, কারণ 1এটি নাল পয়েন্টার ধ্রুবক নয়।

যেহেতু এটি একটি সংকলন সময় সমস্যা (আক্ষরিক অবৈধ মান) আপনি সংকলন সময়ে এটি ধরতে পারেন। এই ফর্মটির একটি ওভারলোড যুক্ত করুন:

void operator[](std::nullptr_t) = delete;

std::nullptr_tএর ধরণ nullptr। এবং এটা ম্যাচ হবে কোন নাল পয়েন্টার ধ্রুবক, এটা হতে 0, 0ULLঅথবা nullptr। এবং যেহেতু ফাংশনটি মুছে ফেলা হয়েছে, এটি ওভারলোড রেজোলিউশনের সময় একটি সংকলন সময় ত্রুটির সৃষ্টি করবে।


এটি এখন পর্যন্ত সেরা সমাধান, সম্পূর্ণরূপে ভুলে গিয়েছি আমি কোনও নুল পয়েন্টারকে ওভারলোড করতে পারি।
কাবানাস

ভিজ্যুয়াল স্টুডিওতে এমনকি "ohNo [0]" নাল মান ব্যতিক্রম ছুঁড়ে ফেলেছে। এর অর্থ কি স্টাড :: স্ট্রিং ক্লাসের নির্দিষ্ট একটি বাস্তবায়ন?
ট্রুথসাইকার

@ পিএমপি কি ফেলা হয় (যদি কিছু থাকে) বাস্তবায়ন নির্দিষ্ট, তবে বিন্দুটি হল স্ট্রিংটি তাদের সকলের মধ্যে একটি নাল পয়েন্টার। এই সমাধানের সাহায্যে আপনি ব্যতিক্রম অংশে পাবেন না, এটি সংকলনের সময় সনাক্ত করা হবে।
কাবানাস

18
@ পিএমপি - std::stringসি ++ স্ট্যান্ডার্ড দ্বারা নির্মাতার কাছে নাল পয়েন্টারটি পাস করার অনুমতি নেই। এটি অপরিজ্ঞাত আচরণ, সুতরাং এমএসভিসি যা খুশি তা করতে পারে (যেমন একটি ব্যতিক্রম ছুঁড়ে দেওয়া)।
গল্পগ্রাহক - আনস্ল্যান্ডার মনিকা

26

একটি বিকল্প হ'ল এটির একটি privateওভারলোড ঘোষণা করা operator[]()যা একটি অবিচ্ছেদ্য যুক্তি গ্রহণ করে, এবং এটি সংজ্ঞায়িত করবে না।

এই বিকল্পটি সমস্ত সি ++ স্ট্যান্ডার্ডের সাথে কাজ করবে (1998-এ), void operator[](std::nullptr_t) = deleteসি -+ 11 থেকে কার্যকর বৈধ বিকল্পগুলির মত নয়।

মেকিং operator[]()একটি privateসদস্য আপনার উদাহরণ একটি রোগ নির্ণয়, ত্রুটি কারণ হবে ohNo[0], যদি না যে অভিব্যক্তি সদস্য ফাংশন দ্বারা বা ব্যবহার করা হয়, friendক্লাসের।

যদি সেই অভিব্যক্তিটি কোনও সদস্য ফাংশন বা friendশ্রেণীর থেকে ব্যবহার করা হয় , কোডটি সংকলন করবে তবে - যেহেতু ফাংশনটি সংজ্ঞায়িত করা হয়নি - সাধারণত বিল্ডটি ব্যর্থ হবে (যেমন একটি অপরিবর্তিত ফাংশনের কারণে লিঙ্কার ত্রুটি)।

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