如何防止修改数组数据?


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

有没有一种方法可以防止仅ptrconst实例中更改数组的内容,而不能“小心”(或远离原始指针)?

我知道我可以做类似的事情

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 '19

2
@marvinIsSacul当然可以,但std::vector::operator[]() const返回const参考
idclev 463035818 '19

@ChrisMM我所期望的,只是想提一下房间里的大象:)
idclev 463035818

Answers:


7

指针不传播const。添加const到类型double*yields double* constconst在取消引用时将导致非左值。

相反,您可以使用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 '19

@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

我同意开销是最小的,但是当性能很关键(内存和时间)时,有理由使用原始指针。有时我会使用a vector然后通过.data()or 获取其内容,然后&vec[0]直接使用它。在共享的情况下,我经常有一个创建和删除指针的所有者,但其他类共享数据。
ChrisMM '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.