จะป้องกันการแก้ไขข้อมูลอาเรย์ได้อย่างไร?


9

ว่าฉันมีชั้นเรียนที่มีลักษณะเช่นนี้ (นี่เป็นเพียงตัวอย่าง):

class A {
    double *ptr;
public:
    A() : ptr( new double[100] ) {}
    A( const A &other ) {
        other.ptr[7] = 15;
    }
    void doNotChangeMyData() const {
        ptr[43] = 14;
    }
    void changeMyData() {
        ptr[43] = 14;
    }
    ~A() { delete[] ptr; }
};

constทั้งในตัวสร้างสำเนาและdoNotChangeMyDataฟังก์ชั่นให้มันเพื่อให้ptrไม่สามารถเปลี่ยนแปลงได้; ptrแต่นี้ยังช่วยให้ฉันเพื่อปรับเปลี่ยนเนื้อหาของอาร์เรย์ที่ชี้ไปตาม

มีวิธีการป้องกันเนื้อหาของptrอาเรย์จากการเปลี่ยนแปลงในconstอินสแตนซ์เท่านั้นสั้น ๆ ของ "ระวัง" (หรือเปลี่ยนจากตัวชี้ดิบ)?

ฉันรู้ว่าฉันสามารถทำอะไรบางอย่างเช่น

void doNotChangeMyData() const {
    const double *const ptr = this->ptr;
    ptr[43] = 14; // then this would fail to compile
}

แต่ฉันไม่ต้องการ ...


1
คุณสามารถใช้std::vector
idclev 463035818

std::vector::operator[]()สามารถแก้ไขค่าได้ใช่ไหม
marvinIsSacul

@ formerlyknownas_463035818 แก้ไขปัญหาเพื่อไม่เลือก;) มันขึ้นเป็นคำถามทางทฤษฎี แต่ใช่vectorจะทำงาน
ChrisMM

2
@marvinIsSacul แน่นอน แต่std::vector::operator[]() constส่งคืนconstข้อมูลอ้างอิง
idclev 463035818

@ChrisMM สิ่งที่ฉันคาดหวังเพียงแค่ต้องการพูดถึงช้างในห้อง :)
idclev 463035818

คำตอบ:


7

พอยน์เตอร์ไม่เผยแพร่ constชี้ไม่ได้เผยแพร่การเพิ่มconstประเภทdouble*ผลตอบแทนdouble* constซึ่งส่งผลให้เกิดความไม่constคุ้มค่าเมื่อถูกยกเลิกการลงทะเบียน

คุณสามารถใช้std::vector:

class A {
    std::vector<double> data(100);
public:
    // no explicit copy ctor or dtor
};

std::array :

class A {
    std::array<double, 100> data{};
public:
    // no explicit copy ctor or dtor
};

หรืออาร์เรย์ในตัว (ไม่แนะนำ):

class A {
    double data[100] {};
public:
    // no explicit copy ctor or dtor
};

constทั้งหมดสามตัวเลือกการเผยแพร่

หากคุณต้องการใช้พอยน์เตอร์อย่างแท้จริง (ไม่แนะนำอย่างยิ่ง) อย่างน้อยใช้ a std::unique_ptrเพื่อหลีกเลี่ยงการจัดการหน่วยความจำด้วยตนเอง คุณสามารถใช้std::experimental::propagate_constกระดาษห่อจากพื้นฐานห้องสมุด 2 TS:

class A {
    std::experimental::propagate_const<std::unique_ptr<double[]>> ptr;
public:
    A()
        : ptr{new double[100] {}}
    {
    }
    // manual copy ctor
    A(const A& other)
        : ptr{new double[100]}
    {
        std::copy_n(other.ptr.get(), 100, ptr.get());
    }
    // defaulted move ctor & dtor
    // assignment operator, etc.
    // ...
};

ยังไม่ได้มาตรฐาน แต่คอมไพเลอร์หลายคนสนับสนุน แน่นอนวิธีการนี้จะด้อยกว่าภาชนะที่เหมาะสม


พยายามทำสิ่งนี้โดยไม่เปลี่ยนประเภทข้อมูลต้นแบบคำถามเชิงทฤษฎีมากกว่าสิ่งใด ถ้าเป็นไปไม่ได้ฉันจะยอมรับมันเป็นไปไม่ได้
ChrisMM

@ChrisMM ฉันได้อัปเดตคำตอบด้วยโซลูชันตัวชี้แล้ว แต่ทำไม :)
LF

"ทำไม" ตอบยากอยากรู้อยากเห็นมากขึ้น "อาร์เรย์ในตัว" หรือstd::arrayไม่ทำงานหากคุณไม่ทราบขนาดขณะรวบรวมข้อมูล vectorเพิ่มค่าใช้จ่าย; unique_ptrไม่ได้เพิ่มค่าใช้จ่าย แต่ถ้าต้องการตัวชี้ที่จะใช้ร่วมกันคุณจะต้องshared_ptrเพิ่มค่าใช้จ่าย ฉันไม่คิดว่า VS สนับสนุนในขณะนี้propagate_const(อย่างน้อยไฟล์ส่วนหัวที่อ้างถึงโดย cppreference ไม่มีอยู่/std:c++latest) :(
ChrisMM

1
@ChrisMM ค่าโสหุ้ยของvectorมักจะประเมินค่า TBH โดยเฉพาะอย่างยิ่งเมื่อเทียบกับความพยายามในการจัดการหน่วยความจำด้วยตนเอง shared_ptrนอกจากนี้ถ้าคุณแบ่งปันคำแนะนำด้วยตนเองคุณต้องใช้จำนวนการอ้างอิงเพื่อให้ค่าใช้จ่ายที่ไม่ได้เป็นเฉพาะที่ ฉันไม่ทราบว่า VS ยังไม่สนับสนุนpropagate_const(GCC และ Clang สนับสนุน IIRC ทั้งสอง) แต่ก็ไม่ยากที่จะแผ่ออกของเราเองตามข้อมูลจำเพาะ
LF

ฉันยอมรับว่าค่าใช้จ่ายน้อยที่สุด แต่มีเหตุผลที่จะใช้ตัวชี้แบบดิบเมื่อประสิทธิภาพมีความสำคัญ (หน่วยความจำและเวลา) บางครั้งฉันก็ใช้vectorเนื้อหาจากนั้นผ่านทาง.data()หรือ&vec[0]ทำงานโดยตรงกับสิ่งนั้นแทน ในกรณีของการแชร์ฉันมักจะมีเจ้าของตัวชี้หนึ่งที่สร้างและลบ แต่คลาสอื่น ๆ แบ่งปันข้อมูล
ChrisMM
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.