عند تنفيذ المشغل[] كيف يجب أن تشمل حدود فحص?

StackOverflow https://stackoverflow.com/questions/1026042

  •  06-07-2019
  •  | 
  •  

سؤال

أولا وقبل كل شيء أعتذر لفترة طويلة تؤدي إلى مثل هذا التبسيط السؤال.

انا تنفيذ الطبقة التي هي بمثابة طويلة جدا 1 الأبعاد مؤشر على ملء الفضاء منحنى أو n-المجموعة تمثل الإحداثيات الديكارتية أن مؤشر يتوافق مع.

class curvePoint
{
public:
    friend class curveCalculate;

    //Construction and Destruction
    curvePoint(): point(NULL), dimensions(0) {}
    virtual ~curvePoint(){if(point!=NULL) delete[] point;}

    //Mutators
    void convertToIndex(){ if(isTuple()) calc(this); }
    void convertToTuple(){ if(isIndex()) calc(this); }
    void setTuple(quint16 *tuple, int size);
    void setIndex(quint16 *index, int size);
    void setAlgorithm(curveType alg){algorithm = alg;}

    //Inspectors
    bool isIndex(){return current==Index;}
    bool isTuple(){return current==Tuple;}
    size_t size(){return dimensions;}
    quint16 operator[](size_t index);

    enum curveType{HilbertCurve, ZCurve, GrayCodeCurve};
    enum status{Index, Tuple};

private:
    curveCalculate calc;
    curveType algorithm;
    quint16 *point;
    size_t dimensions;
    status current;
};

(طول المصفوفة إلى جانب نقطة هو الأبعاد)

على أي حال في تنفيذ المشغل[] كنت أتساءل ما هي أفضل طريقة لتحقيق حدود التحقق.أريد أن تجنب رمي الاستثناءات إذا كان ذلك ممكنا ، و مجموعة كاملة من القيم قابلة للاستخدام من أجل كل عدد في المصفوفة حتى قيمة خاصة للعودة في حالة الخروج من حدود الخطأ غير ممكن أيضا ؛

كنت أفكر في شيء من هذا القبيل على الرغم من تنفيذها في تعريف الفئة:

quint16 curvePoint::operator[](size_t index)
{
    return point[ index % dimensions ];
}

هذا يجعل من ذلك أن لا نترك حدود الصفيف إذا موثقة بشكل جيد وأعتقد أنه سيكون على ما يرام ؛ ومع ذلك, أنا ليري هذا التنفيذ.

هل هذا يبدو مقبولا لدى الآخرين ؟ هل هناك أي طريقة أخرى للقيام حدود التدقيق في حين لا يزال مرضية بلدي القيود ؟

تحرير:حساب أشياء مثل هيلبيرت منحنيات الخ للغاية فوضوي فوضوي بما فيه الكفاية أن كنت لا تريد الإضافية واجهة المكتبات الخاصة بلبنان في الطريق.

بالإضافة إلى ذلك لأنني سوف تضطر إلى تحويل العديد من الآلاف من هؤلاء في كل مرة الأبعاد قاعدة بيانات الاستعلام أنا لا أريد تكلفة إضافية المحكمة الخاصة بلبنان المكالمات وظيفة في هذا المزيج ، إذا كان ذلك ممكنا.

أنا أحب فكرة تأكيد;ولكن إذا كنت أتذكر بشكل صحيح أن يكسر في نسخ الإصدار أليس كذلك ؟

أعتقد أنني يمكن استخدام الاستثناءات التي يبدو أن الجميع يكره ، ولكن أنا باستخدام مكتبات Qt و تجنب تلك الاستثناءات لكل من الأداء وقابلية و كنت أتمنى أن تفعل الشيء نفسه.

هل كانت مفيدة؟

المحلول

وأسهل حل هو أن تفعل كما C ++ نفسها لا. وهذا يحد من كمية من المفاجآت أن المستخدمين سوف تشهد.

وC ++ نفسها يتفق إلى حد ما. كل من السلوك المدمج في [] على مؤشرات وstd::vector::operator[] وغير معروف إذا كنت تستخدم خارج بد من مؤشر مجموعة. إذا كنت تريد حدود التحقق، تكون واضحة واستخدام std::vector::at

وبالتالي، إذا كنت تفعل الشيء نفسه للفئة الخاصة بك، يمكنك توثيق سلوك ملزمة خارج كما "المعيار".

نصائح أخرى

على أي حال في تنفيذ مشغل[] كنت أتساءل ما أفضل طريقة لتحقيق حدود التحقق هو.أريد أن تجنب رمي الاستثناءات إذا كان ذلك ممكنا ، مجموعة كاملة من القيم قابلة للاستخدام كل رقم في المصفوفة بحيث خاص قيمة الإرجاع في حالة من حدود الخطأ غير ممكن أيضا ؛

ثم الخيارات المتبقية هي:

  • تصميم مرن. ما فعلته."إصلاح" إدخال غير صالح حتى أنه يحاول أن يفعل شيئا الأمر الذي يجعل الشعور.ميزة:وظيفة لن تحطم الطائرة.العيب:جاهل المتصلين من الوصول خارج حدود العنصر سوف تحصل على الكذب ونتيجة.تخيل 10-بناء طابق مع الطوابق من 1 إلى 10:

لك: "الذي يعيش في 3rd الكلمة؟"

لي: "مريم".

لك: "الذي يعيش في الطابق 9?"

لي: "جو".

لك: "الذي يعيش في 1,203 rd الكلمة؟"

لي:(الانتظار...1,203 % 10 = 3...) > "مريم".

لك: "نجاح باهر ، ماري يجب أن تتمتع مناظر رائعة من هناك.حتى انها تمتلك شقتين بعد ذلك؟"

  • A منطقي معلمة الإخراج يشير إلى النجاح أو الفشل.هذا الخيار عادة ما ينتهي في غير صالحة للاستعمال جدا البرمجية.العديد من المستخدمين سيتم تجاهل رمز الإرجاع.كنت لا تزال مع ترك ما تعود في عودة أخرى قيمة.

  • تصميم العقد. يؤكدون أن المتصل هو في حدود.(على نهج عملي في C++ ، انظر استثناء أو علة ؟ بواسطة ميرو Samek أو بسيطة لدعم تصميم عقد في C++ عن طريق بيدرو غيريرو.)

  • العودة System.Nullable<quint16>.عفوا, انتظر, هذا ليس C#.حسنا, يمكنك العودة مؤشر إلى quint16.هذا بالطبع لديه الكثير من الآثار التي لن نناقش هنا والتي ربما تجعل هذا الخيار غير قابلة للاستعمال.

خياراتي المفضلة هي:

  • للجمهور واجهة علنا صدر المكتبة:الإدخال سيتم التحقق استثناء سيتم طرح.كنت استبعد هذا الخيار ، لذلك ليس خيارا بالنسبة لك.فإنه لا يزال بلدي اختيار واجهة علنا المكتبة.
  • الداخلية الرمز:تصميم العقد.

وبالنسبة لي، هذا الحل غير مقبول لأنك يمكن أن يختبئ من الصعب جدا العثور على الشوائب. رمي للخروج من استثناء مجموعة هو الطريق للذهاب، أو على الأقل وضع التوكيد في وظيفة.

إذا ما تحتاج إليه هو نوع من مجموعة "دائرية" من النقاط، ثم حل بك على ما يرام. ومع ذلك، بالنسبة لي، يبدو تماما مثل الاختباء missusage المشغل الفهرسة وراء بعض المنطق "آمنة"، لذلك سأكون ضد الحل المقترح.

إذا لا تريد السماح مؤشر الفائض، ثم هل يمكن أن تحقق ورمي استثناء.

quint16 curvePoint::operator[](size_t index)
{
    if( index >= dimensions)
    {
       throw std::overflow_error();
    }
    return point[ index ];
}

إذا كنت تريد أن يكون أقل من النفقات العامة، هل يمكن تجنب استثناء، وذلك باستخدام التأكيدات الوقت التصحيح (نفترض أن مؤشر قدمت صالحا دائما):

quint16 curvePoint::operator[](size_t index)
{
    assert( index < dimensions);
    return point[ index ];
}

ومع ذلك، أقترح أن، بدلا من استخدام نقطة والبعد أعضاء، استخدم الأمراض المنقولة جنسيا :: ناقلات لتخزين نقطة. لديها بالفعل الوصول استنادا مؤشر التي يمكن استخدامها:

quint16 curvePoint::operator[](size_t index)
{
    // points is declared as std::vector< quint16> points;
    return points[ index ];
}

وجود عامل [] أن لا يفشل أبدا يبدو لطيفا، ولكن قد يخفي الخلل في وقت لاحق، إذا كانت وظيفة الدعوة تستخدم إزاحة غير قانوني، وجدت القيمة من بداية العازلة، وعائدات كما لو أنه لا قيمة صالحة.

وأفضل طريقة لتحقيق حدود فحص سيكون لإضافة تأكيد.

quint16 curvePoint::operator[](size_t index)
{
    assert(index < dimensions);
    return point[index];
}

إذا التعليمات البرمجية يعتمد بالفعل على مكتبات دفعة، قد ترغب في استخدام BOOST_ASSERT بدلا من ذلك.

إذا كنت أنت وأود أن تحذو حذو التي وضعتها المحكمة الخاصة بلبنان.

في هذه الحالة std::vector تزود طريقتين: at وهي حدود فحص وoperator[] التي ليست كذلك. وهذا يسمح للعميل أن تقرر مع نسخة للاستخدام. أنا بالتأكيد لا تستخدم % size()، وهذا يخفي مجرد علة. ومع ذلك حدود فحص سيضيف الكثير من النفقات العامة للعندما بالتكرار عبر مجموعة كبيرة، وهذا هو السبب في أنه ينبغي أن يكون اختياريا. على الرغم من أنني أتفق مع غيرها من الملصقات أن يؤكدون على وسوف فكرة جيدة جدا، وهذا يسبب فقط ضربة الأداء في التصحيح يبني.

ويجب عليك أن تنظر أيضا إرجاع الإشارات وتوريد CONST ولا الإصدارات CONST. وفيما يلي التعريفات الدالة ل std::vector :

reference at(size_type _Pos);
const_reference at(size_type _Pos) const;

reference operator[](size_type _Pos);
const_reference operator[](size_type _Pos) const;

وكقاعدة جيدة من التجربة إذا لم أكن متأكدا من كيفية تحديد API أنا ابحث عن أمثلة على كيفية تحديد الآخرين واجهات برمجة التطبيقات المماثلة. أيضا أي وقت مضى عندما تستخدم API وأنا أحاول أن نحكم أو معدل لها، والعثور على بت أحب وكره.

وبفضل التعليق على # ميزة C في منصب دانيال Daranas لقد تمكنت من معرفة حل ممكن. وكما ذكرت في سؤالي أنا باستخدام مكتبات كيو تي. هناك لأتمكن من استخدام QVariant. يمكن تعيين QVariant إلى حالة غير صالحة التي يمكن فحصها من قبل وظيفة الحصول عليها. لذا رمز ستصبح شيئا مثل:

QVariant curvePoint::operator[](size_t index){
    QVariant temp;
    if(index > dimensions){
        temp = QVariant(QVariant::Invalid);
    }
    else{
        temp = QVariant(point[index]);
    }

    return temp;
}

وطبعا هذا لديه القدرة على ادخال بعض الشيء من النفقات العامة نرلي في وظيفة حتى احتمال آخر هو استخدام قالب الزوج.

std::pair<quint16, bool> curvePoint::operator[](size_t index){
    std::pair<quint16, bool> temp;
    if(index > dimensions){
        temp.second = false;
    }
    else{
        temp.second = true;
        temp.first = point[index];
    }
    return temp;
}

وأو أنا يمكن أن تستخدم QPair، التي لديها بالضبط نفس الوظيفة، وسوف تجعل من ذلك أن المحكمة الخاصة بلبنان لا يلزم أن تكون مرتبطة في.

وأنت ربما إضافة استثناء "خارج الحدود" للمشغل [] (أو على الأقل ASSERT).

وهذا يجب أن التقاط أي مشاكل، وخاصة عند التصحيح.

إلا أنا جذريا سوء فهم شيء ما ،

return point[ index % dimensions ];

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

أود أن إما:

  1. رمي استثناء أو التوكيد (على الرغم من أنك قلت أنك لا تريد أن تفعل ذلك)
  2. ببساطة إلغاء مرجعية المرحلة الماضية مجموعة في "الطبيعية" الطريقة (أيفقط تخطي أي التدقيق الداخلي).ميزة على % أنهم أكثر احتمالا (على الرغم من غير معرف غير معرف) للحصول على "غريب" القيم و/أو إلى انتهاك حقوق الوصول

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

أيضا النظر في ما Cătălin قال عن دمج المدمج في المحكمة الخاصة بلبنان مجموعات إذا كان هذا هو المعقول.

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

والمشغل مودولو يعمل بشكل جيد من المستغرب لمؤشرات مجموعة - كما تنفذ مؤشرات سلبية (أي point[-3] = point[dimensions - 3]). هذا أمر سهل للعمل مع، لذلك أنا أنصح شخصيا المشغل مودولو طالما انها موثقة جيدا.

وثمة خيار آخر هو السماح للطالب اختيار السياسة خارج الحدود. النظر فيما يلي:

template <class OutOfBoundsPolicy>
quint16 curvePoint::operator[](size_t index)
{
    index = OutOfBoundsPolicy(index, dimensions);
    return point[index];
}

وثم هل يمكن تحديد العديد من السياسات أن المتصل قد يختار. على سبيل المثال:

struct NoBoundsCheck {
    size_t operator()(size_t index, size_t /* max */) {
        return index;
    }
};

struct WrapAroundIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        return index % max;
    }
};

struct AssertIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        assert(index < max);
        return index % max;
    }
};

struct ThrowIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        if (index >= max) throw std::domain_error;
        return index;
    }
};

struct ClampIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        if (index >= max) index = max - 1;
        return index;
    }
};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top