배열 데이터 수정을 방지하는 방법은 무엇입니까?


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 463,035,818

std::vector::operator[]()값을 바로 수정할 수 있습니까?
marvinIsSacul

@ formerlyknownas_463035818 편집 된 질문이므로 옵션이 아닙니다.) 더 이론적 인 질문이지만 그렇습니다 vector.
ChrisMM

2
확인 @marvinIsSacul,하지만 std::vector::operator[]() const반환 const참조
idclev 463,035,818

@ChrisMM 내가 기대했던 것, 방 안에 코끼리를 언급하고 싶었다 :)
idclev 463035818

답변:


7

포인터는 전파되지 않습니다 const. const유형에 추가하면 을 double*산출 double* const하여 const역 참조 될 때 l 값이 아닙니다.

대신, 당신은 사용할 수 있습니다 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
};

또는 내장 배열 (권장되지 않음) :

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

세 가지 옵션 모두 전파 const됩니다.

당신이 경우 정말 (권장하지 않음) 포인터를 사용하려면, 적어도를 사용하여 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.