การใช้ BOOST_STRONG_TYPEDEF เพื่อแยกประเภทอาร์กิวเมนต์ แต่ทำให้เกิดข้อผิดพลาดในการทำ seg

Jan 09 2021

ฉันมีวิธีการที่ต้องการตัวแปรหลายตัวในประเภท enum เดียวกัน เพื่อให้คอมไพลเลอร์ตรวจพบว่าฉันส่งอาร์กิวเมนต์ผิดที่ฉันใช้BOOST_STRONG_TYPEDEFอยู่หรือไม่ อย่างไรก็ตามฉันได้รับข้อผิดพลาดเกี่ยวกับ seg เมื่อฉันสร้างอินสแตนซ์และเปรียบเทียบภายในคำสั่ง IF

เวอร์ชั่น Boost คือ 1.74

enum class Testable
{
    UNDEFINED,
    A,
    B
};

BOOST_STRONG_TYPEDEF(Testable, SomeType)

int main()
{  
    SomeType abc{Testable::UNDEFINED};
    std::cout << "START" << std::endl;
    
    if(abc == Testable::UNDEFINED)  // Seg faults here
    {
        volatile int j = 0;
    }
    
    std::cout << "FINISH" << std::endl;
}

GDB backtrace แนะนำว่าเป็นสแต็กโอเวอร์โฟลว์ / เรียกซ้ำ:

#1    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:
#2    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:
#3    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:
#4    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:
#5    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:
#6    0x00007ffff74c5d9d in boost::operators_impl::operator== (y=@0x7fffffcc9e44:

BOOST_STRONG_TYPEDEFมีเอกสารไม่มากสำหรับการเป็น ฉันใช้ผิดหรือเปล่า?

เวอร์ชั่น Boost คือ 1.74 ฉันใช้เสียงดัง

คำตอบ

1 sehe Jan 09 2021 at 20:09

Sanitizer กล่าว

==3044==ERROR: AddressSanitizer: stack-overflow on address 0x7ffcc58b3ff8 (pc 0x56310c340e84 bp 0x7ffcc58b4000 sp 0x7ffcc58b3ff
0 T0)
    #0 0x56310c340e84 in boost::operators_impl::operator==(Testable const&, SomeType const&) /home/sehe/custom/boost_1_75_0/boo

ปัญหาคือ STRONG_TYPEDEF ของ Boost ทำให้ประเภทอนุพันธ์เรียงลำดับโดยสิ้นเชิงด้วยประเภทฐาน:

struct SomeType
    : boost::totally_ordered1<SomeType, boost::totally_ordered2<SomeType, Testable>>
{
    Testable t;
    explicit SomeType(const Testable& t_) noexcept((boost::has_nothrow_copy_constructor<Testable>::value)) : t(t_) {}
    SomeType() noexcept( (boost::has_nothrow_default_constructor<Testable>::value)) : t() {}
    SomeType(const SomeType& t_) noexcept( (boost::has_nothrow_copy_constructor<Testable>::value)) : t(t_.t) {}
    SomeType& operator=(const SomeType& rhs) noexcept((boost::has_nothrow_assign<Testable>::value)) {
        t = rhs.t;
        return *this;
    }
    SomeType& operator=(const Testable& rhs) noexcept((boost::has_nothrow_assign<Testable>::value)) {
        t = rhs;
        return *this;
    }
    operator const Testable&() const { return t; }
    operator Testable&() { return t; }
    bool operator==(const SomeType& rhs) const { return t == rhs.t; }
    bool operator<(const SomeType& rhs) const { return t < rhs.t; }
};

หากคุณลบแหล่งที่มาของการแปลงโดยนัย:

struct SomeType
    : boost::totally_ordered1<SomeType
      /*, boost::totally_ordered2<SomeType, Testable>*/>
{
     // ...

มัน JustWorks (TM) ฉันขอเถียงว่าคุณควรสร้างตัวดำเนินการแปลงexplicitด้วยและทำการแคสต์เสมอ:

อาศัยอยู่บน Coliru

#include <boost/serialization/strong_typedef.hpp>
#include <iostream>

enum class Testable { UNDEFINED, A, B };
       
struct SomeType
    : boost::totally_ordered1<SomeType
      /*, boost::totally_ordered2<SomeType, Testable>*/>
{
    Testable t;
    explicit SomeType(const Testable& t_) noexcept((boost::has_nothrow_copy_constructor<Testable>::value)) : t(t_) {}
    SomeType() noexcept( (boost::has_nothrow_default_constructor<Testable>::value)) : t() {}
    SomeType(const SomeType& t_) noexcept( (boost::has_nothrow_copy_constructor<Testable>::value)) : t(t_.t) {}
    SomeType& operator=(const SomeType& rhs) noexcept((boost::has_nothrow_assign<Testable>::value)) {
        t = rhs.t;
        return *this;
    }
    SomeType& operator=(const Testable& rhs) noexcept((boost::has_nothrow_assign<Testable>::value)) {
        t = rhs;
        return *this;
    }
    explicit operator const Testable&() const { return t; }
    explicit operator Testable&() { return t; }
    bool operator==(const SomeType& rhs) const { return t == rhs.t; }
    bool operator<(const SomeType& rhs) const { return t < rhs.t; }
};

int main() {
    SomeType abc{ Testable::UNDEFINED };
    std::cout << "START" << std::endl;

    if (abc == SomeType{Testable::UNDEFINED}) {
        volatile int j = 0;
    }

    std::cout << "FINISH" << std::endl;
}