c++ - منع وظيفة أخذ const std:: string & من قبول 0




implicit-conversion (2)

بقيمة ألف كلمة:

#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) لإدخال الطريقة ، مما يؤدي إلى نفس المشكلة (خطأ google أعلاه) دون سبب وجيه.

سؤال

هل هناك أي حل لإصلاح هذا الأمر على جانب الفصل ، لذلك لا يشعر مستخدم واجهة برمجة التطبيقات بهذا ويتم اكتشاف الخطأ في وقت الترجمة؟

هذا هو ، إضافة الزائد

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

ليس حلا جيدا


السبب std::string(0) صحيح ، بسبب 0 كونه ثابت مؤشر فارغة. لذلك يطابق المنشئ أخذ المؤشر. بعد ذلك ، يتعارض مع الشرط المسبق الذي قد لا يمرر المرء مؤشرًا خاليًا إلى std::string . سيتم تفسير 0 الحرفي فقط على أنه ثابت مؤشر فارغ ، إذا كانت قيمة وقت التشغيل في int فلن تواجهك هذه المشكلة (لأنه عندئذٍ ستبحث دقة التحميل الزائد عن تحويل int بدلاً من ذلك). لا يمثل الحرفي 1 مشكلة ، لأن 1 ليس ثابتًا بمؤشر لاغية.

نظرًا لأنها مشكلة في وقت الترجمة (القيم الحرفية غير الصالحة) ، يمكنك التقاطها في وقت الترجمة. أضف حمولة زائدة من هذا النموذج:

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

std::nullptr_t هو نوع nullptr . وسوف تتطابق مع أي ثابت مؤشر فارغة ، سواء كان 0 أو nullptr أو nullptr . ونظرًا لأن الوظيفة يتم حذفها ، فإنها ستتسبب في حدوث خطأ وقت الترجمة أثناء دقة التحميل الزائد.


يتمثل أحد الخيارات في الإعلان عن حمل زائد private operator[]() يقبل وسيطة متكاملة ، ولا يحددها.

سيعمل هذا الخيار مع جميع معايير C ++ (1998 on) ، على عكس الخيارات مثل void operator[](std::nullptr_t) = delete الصالحة من C ++ 11.

سيؤدي جعل operator[]() عضوًا private إلى حدوث خطأ يمكن ohNo[0] ، إلا إذا تم استخدام هذا التعبير بواسطة وظيفة عضو أو friend للفصل.

إذا تم استخدام هذا التعبير من وظيفة عضو أو friend للفئة ، فسوف يتم تجميع الشفرة ولكن - نظرًا لأن الوظيفة غير محددة - ستفشل البنية بشكل عام (على سبيل المثال ، خطأ في رابط بسبب وظيفة غير محددة).





implicit-conversion