Làm thế nào để ngăn chặn sửa đổi dữ liệu mảng?


9

Nói rằng tôi có một lớp trông như thế này (đây chỉ là một ví dụ):

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; }
};

Trong constcả hàm tạo sao chép và doNotChangeMyDatahàm làm cho nó ptrkhông thể thay đổi; tuy nhiên, điều này vẫn cho phép tôi sửa đổi nội dung của mảng được chỉ bởi ptr.

Có cách nào để ngăn nội dung của ptrmảng chỉ bị thay đổi trong các consttrường hợp, không phải là "cẩn thận" (hoặc thay đổi khỏi con trỏ thô) không?

Tôi biết tôi có thể làm một cái gì đó như

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

Nhưng tôi không muốn phải ...


1
bạn có thể sử dụng mộtstd::vector
idclev 463035818

std::vector::operator[]()Có thể sửa đổi giá trị phải không?
marvinIsSacul

@ trước đây là Unknown_463035818 Câu hỏi đã được chỉnh sửa nên không phải là một lựa chọn;) Đây là một câu hỏi lý thuyết, nhưng vâng, vectorsẽ hoạt động.
ChrisMM

2
@marvinIsSacul chắc chắn, nhưng std::vector::operator[]() consttrả về một consttham chiếu
idclev 463035818

@ChrisMM những gì tôi mong đợi, chỉ muốn đề cập đến con voi trong phòng :)
idclev 463035818

Câu trả lời:


7

Con trỏ không tuyên truyền const. Thêm constvào double*năng suất loại double* const, dẫn đến constgiá trị không bị mất khi bị hủy đăng ký.

Thay vào đó, bạn có thể sử dụng std::vector:

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

a std::array:

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

hoặc một mảng dựng sẵn (không được khuyến nghị):

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

Tất cả ba tùy chọn tuyên truyền const.

Nếu bạn thực sự muốn sử dụng con trỏ (không nên sử dụng), ít nhất hãy sử dụng a std::unique_ptrđể tránh quản lý bộ nhớ thủ công. Bạn có thể sử dụng std::experimental::propagate_consttrình bao bọc từ thư viện cơ bản 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.
    // ...
};

Nó chưa có trong tiêu chuẩn, nhưng nhiều trình biên dịch hỗ trợ nó. Tất nhiên, cách tiếp cận này là kém hơn so với các container thích hợp.


cố gắng làm điều này mà không thay đổi kiểu dữ liệu cơ bản, nhiều câu hỏi lý thuyết hơn bất cứ điều gì. Nếu không thể, thì tôi sẽ chấp nhận nó là không thể.
ChrisMM

@ChrisMM Tôi đã cập nhật câu trả lời bằng giải pháp con trỏ. Nhưng tại sao :)
LF

"Tại sao" rất khó để trả lời, thêm một sự tò mò. "Mảng tích hợp" hoặc std::arraykhông hoạt động, nếu bạn không biết kích thước tại thời gian biên dịch. vectorthêm chi phí; unique_ptrkhông thêm chi phí nhưng nếu con trỏ cần được chia sẻ, thì bạn cần shared_ptrthêm chi phí. Tôi không nghĩ rằng VS hiện đang hỗ trợ propagate_const(ít nhất là tệp tiêu đề được đề cập bởi cppreference không tồn tại với /std:c++latest) :(
ChrisMM

1
@ChrisMM Chi phí hoạt động của vectorTBH thường được đánh giá quá cao, đặc biệt là so với nỗ lực quản lý bộ nhớ thủ công. Ngoài ra, nếu bạn chia sẻ các con trỏ theo cách thủ công, bạn phải sử dụng số tham chiếu, do đó, chi phí không đặc biệt shared_ptr. Tôi không biết rằng VS chưa hỗ trợ propagate_const(cả GCC và Clang đều hỗ trợ IIRC), nhưng không khó để tung ra sản phẩm của chúng tôi theo thông số kỹ thuật.
LF

Tôi đồng ý rằng chi phí là tối thiểu, nhưng có những lý do để sử dụng con trỏ thô khi hiệu suất rất quan trọng (bộ nhớ và thời gian). Đôi khi tôi sử dụng một vectorsau đó lấy nội dung của nó thông qua .data()hoặc &vec[0]thay vào đó làm việc trực tiếp với nó. Trong trường hợp chia sẻ, tôi thường có một chủ sở hữu con trỏ tạo và xóa, nhưng các lớp khác chia sẻ dữ liệu.
ChrisMM
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.